home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 24 / Amiga Format AFCD24 (Feb 1998, Issue 108).iso / -in_the_mag- / emulation / macos / uae069b2.src.cpt.hqx / UAE069ß2.SRC.CPT / uae069fl2.src / filesys.c < prev    next >
C/C++ Source or Header  |  1997-06-18  |  75KB  |  2,710 lines

  1.  /*
  2.   * UAE - The Un*x Amiga Emulator
  3.   *
  4.   * Unix file system handler for AmigaDOS
  5.   *
  6.   * Copyright 1996 Ed Hanway
  7.   * Copyright 1996, 1997 Bernd Schmidt
  8.   *
  9.   * Version 0.4: 970308
  10.   *
  11.   * Based on example code (c) 1988 The Software Distillery
  12.   * and published in Transactor for the Amiga, Volume 2, Issues 2-5.
  13.   * (May - August 1989)
  14.   *
  15.   * Known limitations:
  16.   * Does not support ACTION_INHIBIT (big deal).
  17.   * Does not support any 2.0+ packet types (except ACTION_SAME_LOCK)
  18.   * Does not support removable volumes.
  19.   * May not return the correct error code in some cases.
  20.   * Does not check for sane values passed by AmigaDOS.  May crash the emulation
  21.   * if passed garbage values.
  22.   * Could do tighter checks on malloc return values.
  23.   * Will probably fail spectacularly in some cases if the filesystem is
  24.   * modified at the same time by another process while UAE is running.
  25.   */
  26.  
  27. #if 1
  28.  
  29. #include "sysconfig.h"
  30. #include "sysdeps.h"
  31.  
  32. #include "config.h"
  33. #include "options.h"
  34. #include "uae.h"
  35. #include "my_memory.h"
  36. #include "custom.h"
  37. #include "readcpu.h"
  38. #include "newcpu.h"
  39. #include "xwin.h"
  40. #include "filesys.h"
  41. #include "autoconf.h"
  42. #include "compiler.h"
  43. #include "threaddep/penguin.h"
  44.  
  45. /////////// ATB ///////////
  46.  
  47. //sys.unistd.H
  48. #define F_OK 0
  49. #define X_OK 0x01
  50. #define W_OK 0x02
  51. #define R_OK 0x04
  52.  
  53. // sys/stat.h
  54. #define S_IRWXU 0000700
  55. #define S_IRUSR 0000400
  56. #define S_IWUSR 0000200
  57. #define S_IXUSR 0000100
  58.  
  59. // sys/errno.h
  60. #define EACCES          13
  61.  
  62. // chmod
  63. int chmod(const char *path, mode_t mode);
  64.  
  65. int chmod(const char *path, mode_t mode)
  66. {
  67. return 0;
  68. }
  69.  
  70. #define DIR long
  71.  
  72. int access(const char *name, int mode)
  73. {
  74.     return -1;
  75. }
  76.  
  77. /////////////////////////
  78.  
  79. #undef TRACING_ENABLED
  80. #ifdef TRACING_ENABLED
  81. #define TRACE(x)    do { sprintf x; write_log(warning_buffer); } while(0)
  82. #define DUMPLOCK(u,x)    dumplock(u,x)
  83. #else
  84. #define TRACE(x)
  85. #define DUMPLOCK(u,x)
  86. #endif
  87.  
  88. #define MAKE_CASE_INSENSITIVE
  89.  
  90. /* errors */
  91. #define ERROR_NO_FREE_STORE        103
  92. #define ERROR_OBJECT_IN_USE        202
  93. #define ERROR_OBJECT_EXISTS        203
  94. #define ERROR_DIR_NOT_FOUND        204
  95. #define ERROR_OBJECT_NOT_FOUND        205
  96. #define ERROR_ACTION_NOT_KNOWN        209
  97. #define ERROR_INVALID_LOCK        211
  98. #define ERROR_OBJECT_WRONG_TYPE        212
  99. #define ERROR_DISK_WRITE_PROTECTED    214
  100. #define ERROR_DIRECTORY_NOT_EMPTY    216
  101. #define ERROR_DEVICE_NOT_MOUNTED    218
  102. #define ERROR_SEEK_ERROR        219
  103. #define ERROR_DISK_FULL            221
  104. #define ERROR_DELETE_PROTECTED        222
  105. #define ERROR_WRITE_PROTECTED        223
  106. #define ERROR_READ_PROTECTED        224
  107. #define ERROR_NO_MORE_ENTRIES        232
  108. #define ERROR_NOT_IMPLEMENTED        236
  109.  
  110.  
  111. #ifndef DONT_HAVE_POSIX
  112. static long dos_errno(void)
  113. {
  114.     int e = errno;
  115.  
  116.     switch(e) {
  117. /*
  118.      case ENOMEM:    return ERROR_NO_FREE_STORE;
  119.      case EEXIST:    return ERROR_OBJECT_EXISTS;
  120.      case EACCES:    return ERROR_WRITE_PROTECTED;
  121.      case ENOENT:    return ERROR_OBJECT_NOT_FOUND;
  122.      case ENOTDIR:    return ERROR_OBJECT_WRONG_TYPE;
  123.      case ENOSPC:    return ERROR_DISK_FULL;
  124.      case EBUSY:           return ERROR_OBJECT_IN_USE;
  125.      case EISDIR:    return ERROR_OBJECT_WRONG_TYPE;
  126. #if defined(ETXTBSY)
  127.      case ETXTBSY:    return ERROR_OBJECT_IN_USE;
  128. #endif
  129. #if defined(EROFS)
  130.      case EROFS:           return ERROR_DISK_WRITE_PROTECTED;
  131. #endif
  132. #if defined(ENOTEMPTY)
  133. #if ENOTEMPTY != EEXIST
  134.      case ENOTEMPTY:    return ERROR_DIRECTORY_NOT_EMPTY;
  135. #endif
  136. #endif
  137. */
  138.      default:
  139.     TRACE((warning_buffer, "Unimplemented error %s\n", strerror(e)));
  140.     return ERROR_NOT_IMPLEMENTED;
  141.     }
  142. }
  143. #endif
  144.  
  145. /*
  146.  * This _should_ be no issue for us, but let's rather use a guaranteed 
  147.  * thread safe function if we have one.
  148.  * Well, let's use it once it works.
  149.  */
  150. #if 0 && defined HAVE_READDIR_R
  151.  
  152. static struct dirent *my_readdir (DIR *dirstream, struct dirent *space)
  153. {
  154.     struct dirent *loc;
  155.     if (readdir_r (dirstream, space, &loc) == 0) {
  156.     /* Success */
  157.     return loc;
  158.     }
  159.     return 0;
  160. }
  161.  
  162. #else
  163. #define my_readdir(dirstream, space) readdir(dirstream)
  164. #endif
  165.  
  166. #define FS_STARTUP 0
  167. #define FS_GO_DOWN 1
  168.  
  169. /* AmigaOS "keys" */
  170. struct a_inode {
  171.     struct a_inode *next, *prev;
  172.     struct a_inode *parent;
  173.     struct a_inode *child, *sibling; /* @@@ implement hash tables or something to make this efficient */
  174.     char *aname;
  175.     char *nname;
  176.     int amigaos_mode;
  177.     int shlock;
  178.     uae_u32 uniq;
  179.     unsigned int dir:1;
  180.     unsigned int elock:1;
  181. };
  182.  
  183. typedef struct {
  184.     char *devname; /* device name, e.g. UAE0: */
  185.     uaecptr devname_amiga;
  186.     uaecptr startup;
  187.     char *volname; /* volume name, e.g. CDROM, WORK, etc. */
  188.     char *rootdir; /* root unix directory */
  189.     int readonly; /* disallow write access? */
  190.     int devno;
  191.     smp_comm_pipe *unit_pipe, *back_pipe;
  192.     penguin_id tid;
  193.     struct _unit *volatile self;
  194. } UnitInfo;
  195.  
  196. #define MAX_UNITS 20
  197. static int num_units = 0, num_filesys_units = 0;
  198. static UnitInfo ui[MAX_UNITS];
  199. uaecptr filesys_initcode;
  200. static uae_u32 fsdevname, hardfileseglist, filesys_configdev;
  201. static uaecptr filesys_parampacket;
  202.  
  203. void add_filesys_unit(char *volname, char *rootdir, int readonly)
  204. {
  205.     if (num_units >= MAX_UNITS) {
  206.     write_log ("Maximum number of file systems mounted.\n");
  207.     return;
  208.     }
  209.  
  210.     if (volname != 0) {
  211.     num_filesys_units++;
  212.     ui[num_units].volname = my_strdup(volname);    
  213.     } else
  214.     ui[num_units].volname = 0;
  215.     ui[num_units].rootdir = my_strdup(rootdir);
  216.     ui[num_units].readonly = readonly;
  217.  
  218.     num_units++;
  219. }
  220.  
  221. int kill_filesys_unit(char *volname)
  222. {
  223.     size_t l = strlen(volname);
  224.     int i;
  225.  
  226.     if (l == 0)
  227.     return -1;
  228.  
  229.     if (volname[l-1] == ':')
  230.     l--;
  231.     
  232.     for (i = 0; i < num_units; i++) {
  233.     if (ui[i].volname != 0
  234.         && strlen(ui[i].volname) == l
  235.         && strncmp(ui[i].volname, volname, l) == 0)
  236.         break;
  237.     }
  238.     if (i == num_units)
  239.     return -1;
  240.  
  241.     num_units--;
  242.     for (; i < num_units; i++) {
  243.     ui[i] = ui[i+1];
  244.     }
  245.     return 0;
  246. }
  247.  
  248. void filesys_store_devinfo (uae_u8 *where)
  249. {
  250.     int i;
  251.  
  252.     do_put_mem_long ((uae_u32 *)where, EXPANSION_explibname);
  253.     do_put_mem_long ((uae_u32 *)(where + 4), filesys_configdev);
  254.     do_put_mem_long ((uae_u32 *)(where + 8), EXPANSION_doslibname);
  255.     do_put_mem_long ((uae_u32 *)(where + 12), num_units);
  256.  
  257.     where += 16;
  258.  
  259.     for (i = 0; i < num_units; i++) {
  260.     int is_hardfile = ui[i].volname == 0;
  261.     uae_u32 *thisdev = (uae_u32 *)where;
  262.     
  263.     do_put_mem_long (thisdev, ui[i].devname_amiga);    
  264.     do_put_mem_long (thisdev + 1, is_hardfile ? ROM_hardfile_resname : fsdevname);
  265.     do_put_mem_long (thisdev + 2, ui[i].devno);
  266.     do_put_mem_long (thisdev + 3, is_hardfile);
  267.  
  268.     where += 16;
  269.     }
  270. }
  271.  
  272. int sprintf_filesys_unit(char *buffer, int num)
  273. {
  274.     if (num >= num_units)
  275.     return -1;
  276.     if (ui[num].volname != 0)
  277.     sprintf(buffer, "%s: %s %s", ui[num].volname, ui[num].rootdir,
  278.         ui[num].readonly ? "ro" : "");
  279.     else
  280.     sprintf(buffer, "Hardfile \"UAE0:\", size %d bytes",
  281.         hardfile_size);
  282.     return 0;
  283. }
  284.  
  285. void write_filesys_config(FILE *f)
  286. {
  287.     int i;
  288.     for (i = 0; i < num_units; i++) {
  289.     if (ui[i].volname != 0) {
  290.         fprintf(f, "-%c %s:%s\n", ui[i].readonly ? 'M' : 'm',
  291.             ui[i].volname, ui[i].rootdir);
  292.     }
  293.     }
  294. }
  295.  
  296. /* minimal AmigaDOS definitions */
  297.  
  298. /* field offsets in DosPacket */
  299. #define dp_Type 8
  300. #define dp_Res1    12
  301. #define dp_Res2 16
  302. #define dp_Arg1 20
  303. #define dp_Arg2 24
  304. #define dp_Arg3 28
  305. #define dp_Arg4 32
  306.  
  307. /* result codes */
  308. #define DOS_TRUE (-1L)
  309. #define DOS_FALSE (0L)
  310.  
  311. /* packet types */
  312. #define ACTION_CURRENT_VOLUME    7
  313. #define ACTION_LOCATE_OBJECT    8
  314. #define ACTION_RENAME_DISK    9
  315. #define ACTION_FREE_LOCK    15
  316. #define ACTION_DELETE_OBJECT    16
  317. #define ACTION_RENAME_OBJECT    17
  318. #define ACTION_COPY_DIR        19
  319. #define ACTION_SET_PROTECT    21
  320. #define ACTION_CREATE_DIR    22
  321. #define ACTION_EXAMINE_OBJECT    23
  322. #define ACTION_EXAMINE_NEXT    24
  323. #define ACTION_DISK_INFO    25
  324. #define ACTION_INFO        26
  325. #define ACTION_FLUSH        27
  326. #define ACTION_SET_COMMENT    28
  327. #define ACTION_PARENT        29
  328. #define ACTION_SET_DATE        34
  329. #define ACTION_SAME_LOCK    40
  330. #define ACTION_FIND_WRITE    1004
  331. #define ACTION_FIND_INPUT    1005
  332. #define ACTION_FIND_OUTPUT    1006
  333. #define ACTION_END        1007
  334. #define ACTION_SEEK        1008
  335. #define ACTION_IS_FILESYSTEM    1027
  336. #define ACTION_READ        'R'
  337. #define ACTION_WRITE        'W'
  338.  
  339. #define DISK_TYPE        0x444f5301 /* DOS\1 */
  340.  
  341. typedef struct {
  342.     uae_u32 uniq;
  343.     struct a_inode *aino;
  344.     DIR* dir;
  345. } ExamineKey;
  346.  
  347. typedef struct key {
  348.     struct key *next;
  349.     struct a_inode *aino;
  350.     uae_u32 uniq;
  351.     int fd;
  352.     off_t file_pos;
  353. } Key;
  354.  
  355. /* Since ACTION_EXAMINE_NEXT is so braindamaged, we have to keep
  356.  * some of these around
  357.  */
  358.  
  359. #define EXKEYS 100
  360. #define MAX_AINO_HASH 128
  361.  
  362. /* handler state info */
  363.  
  364. typedef struct _unit {
  365.     struct _unit *next;
  366.  
  367.     /* Amiga stuff */
  368.     uaecptr    dosbase;
  369.     uaecptr    volume;
  370.     uaecptr    port;    /* Our port */
  371.     uaecptr    locklist;
  372.  
  373.     /* Native stuff */
  374.     uae_s32    unit;    /* unit number */
  375.     UnitInfo    ui;    /* unit startup info */
  376.     char    tmpbuf3[256];
  377.  
  378.     /* Dummy message processing */
  379.     uaecptr    dummy_message;
  380.     volatile unsigned int cmds_sent;
  381.     volatile unsigned int cmds_complete;
  382.     volatile unsigned int cmds_acked;
  383.  
  384.     /* ExKeys */
  385.     ExamineKey    examine_keys[EXKEYS];
  386.     int        next_exkey;
  387.  
  388.     /* Keys */
  389.     struct key*    keys;
  390.     uae_u32    key_uniq;
  391.     uae_u32    a_uniq;
  392.     
  393.     struct a_inode rootnode;
  394.     unsigned long aino_cache_size;
  395.     struct a_inode *aino_hash[MAX_AINO_HASH];
  396.     unsigned long nr_cache_hits;
  397.     unsigned long nr_cache_lookups;
  398.     
  399.     /* Reset handling */
  400.     uae_sem_t    reset_sync_sem;
  401.     int        reset_state;
  402. } Unit;
  403.  
  404. typedef uae_u8 *dpacket;
  405. #define PUT_PCK_RES1(p,v) do { do_put_mem_long ((uae_u32 *)((p) + dp_Res1), (v)); } while (0)
  406. #define PUT_PCK_RES2(p,v) do { do_put_mem_long ((uae_u32 *)((p) + dp_Res2), (v)); } while (0)
  407. #define GET_PCK_TYPE(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Type))))
  408. #define GET_PCK_RES1(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Res1))))
  409. #define GET_PCK_RES2(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Res2))))
  410. #define GET_PCK_ARG1(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Arg1))))
  411. #define GET_PCK_ARG2(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Arg2))))
  412. #define GET_PCK_ARG3(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Arg3))))
  413. #define GET_PCK_ARG4(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Arg4))))
  414.  
  415. static char *bstr1 (uaecptr addr)
  416. {
  417.     static char buf[256];
  418.     int i;
  419.     int n = get_byte(addr);
  420.     addr++;
  421.  
  422.     for(i = 0; i < n; i++, addr++)
  423.     buf[i] = get_byte(addr);
  424.     buf[i] = 0;
  425.     return buf;
  426. }
  427.  
  428. static char *bstr (Unit *unit, uaecptr addr)
  429. {
  430.     int i;
  431.     int n = get_byte(addr);
  432.  
  433.     addr++;
  434.     for(i = 0; i < n; i++, addr++)
  435.     unit->tmpbuf3[i] = get_byte(addr);
  436.     unit->tmpbuf3[i] = 0;
  437.     return unit->tmpbuf3;
  438. }
  439.  
  440. static char *bstr_cut (Unit *unit, uaecptr addr)
  441. {
  442.     char *p = unit->tmpbuf3;
  443.     int i, colon_seen = 0;
  444.     int n = get_byte (addr);
  445.  
  446.     addr++;
  447.     for(i = 0; i < n; i++, addr++) {
  448.     uae_u8 c = get_byte(addr);
  449.     unit->tmpbuf3[i] = c;
  450.     if (c == '/' || (c == ':' && colon_seen++ == 0))
  451.         p = unit->tmpbuf3 + i + 1;
  452.     }
  453.     unit->tmpbuf3[i] = 0;
  454.     return p;
  455. }
  456.  
  457. static Unit *units = 0;
  458. static int unit_num = 0;
  459.  
  460. static Unit*
  461. find_unit(uaecptr port)
  462. {
  463.     Unit* u;
  464.     for(u = units; u; u = u->next)
  465.     if(u->port == port)
  466.         break;
  467.  
  468.     return u;
  469. }
  470.  
  471. static int get_file_attrs (struct a_inode *aino)
  472. {
  473.     struct stat statbuf;
  474.     if (-1 == stat (aino->nname, &statbuf))
  475.     return dos_errno ();
  476.     aino->dir = S_ISDIR (statbuf.st_mode) ? 1 : 0;
  477.     aino->amigaos_mode = 
  478. #ifndef __DOS__
  479.     (S_IXUSR & statbuf.st_mode ? 0 : A_FIBF_EXECUTE) |
  480. #endif
  481.     (S_IWUSR & statbuf.st_mode ? 0 : A_FIBF_WRITE) |
  482. #if 0 /* This makes it impossible to overwrite those. */
  483.     (S_IWUSR & statbuf.st_mode ? 0 : A_FIBF_DELETE) |
  484. #endif
  485.     (S_IRUSR & statbuf.st_mode ? 0 : A_FIBF_READ);
  486.     return 0;
  487. };
  488.  
  489. static int set_file_attrs (struct a_inode *aino, int mask)
  490. {
  491.     struct stat statbuf;
  492.     int mode;
  493.  
  494.     if (-1 == stat(aino->nname, &statbuf))
  495.     return ERROR_OBJECT_NOT_FOUND;
  496.  
  497.     mode = statbuf.st_mode;
  498. #ifdef __unix 
  499.     /* Unix dirs behave differently than AmigaOS ones. Just allow anything. */
  500.     if (aino->dir) {
  501.     mask = 0;
  502.     }
  503. #endif
  504.     if (mask & A_FIBF_READ)
  505.     mode &= ~S_IRUSR;
  506.     else
  507.     mode |= S_IRUSR;
  508.  
  509.     if ((mask & A_FIBF_WRITE) != 0 || (mask & A_FIBF_DELETE) != 0)
  510.     mode &= ~S_IWUSR;
  511.     else
  512.     mode |= S_IWUSR;
  513.  
  514.     if (mask & A_FIBF_EXECUTE)
  515.     mode &= ~S_IXUSR;
  516.     else
  517.     mode |= S_IXUSR;
  518.  
  519.     if (-1 == chmod(aino->nname, mode))
  520.     return dos_errno();
  521.  
  522.     aino->amigaos_mode = mask;
  523.  
  524.     return 0;
  525. }
  526.  
  527. static void prepare_for_open (char *name)
  528. {
  529. #if 0
  530.     struct stat statbuf;
  531.     int mode;
  532.  
  533.     if (-1 == stat (name, &statbuf))
  534.     return;
  535.  
  536.     mode = statbuf.st_mode;
  537.     mode |= S_IRUSR;
  538.     mode |= S_IWUSR;
  539.     mode |= S_IXUSR;
  540.     chmod (name, mode);
  541. #endif
  542. }
  543.  
  544. static void de_recycle_aino (Unit *unit, struct a_inode *aino)
  545. {
  546.     if (aino->next == 0 || aino == &unit->rootnode)
  547.     return;
  548.     aino->next->prev = aino->prev;
  549.     aino->prev->next = aino->next;
  550.     aino->next = aino->prev = 0;
  551.     unit->aino_cache_size--;
  552. }
  553.  
  554. static void recycle_aino (Unit *unit, struct a_inode *aino)
  555. {
  556.     if (aino->dir || aino->shlock > 0 || aino->elock || aino == &unit->rootnode)
  557.     /* Still in use */
  558.     return;
  559.  
  560.     /* Chain it into circular list. */
  561.     aino->next = unit->rootnode.next;
  562.     aino->prev = &unit->rootnode;
  563.     aino->prev->next = aino;
  564.     aino->next->prev = aino;
  565.     unit->aino_cache_size++;
  566.     if (unit->aino_cache_size > 500) {
  567.     /* Reap a few. */
  568.     int i = 0;
  569.     while (i < 50) {
  570.         struct a_inode **aip;
  571.         aip = &unit->rootnode.prev->parent->child;
  572.         for (;;) {
  573.         aino = *aip;
  574.         if (aino == 0)
  575.             break;
  576.  
  577.         if (aino->next == 0)
  578.             aip = &aino->sibling;
  579.         else {
  580.             int hash = aino->uniq % MAX_AINO_HASH;
  581.             if (unit->aino_hash[hash] == aino)
  582.             unit->aino_hash[hash] = 0;
  583.  
  584.             aino->next->prev = aino->prev;
  585.             aino->prev->next = aino->next;
  586.             *aip = aino->sibling;
  587.             i++;
  588.             
  589.             if (aino->shlock > 0 || aino->elock)
  590.             write_log ("panic: freeing locked a_inode!\n");
  591.  
  592.             free (aino->nname);
  593.             free (aino->aname);
  594.             free (aino);
  595.         }
  596.         }
  597.     }
  598. #if 0
  599.     {
  600.         char buffer[40];
  601.         sprintf (buffer, "%d ainos reaped.\n", i);
  602.         write_log (buffer);
  603.     }
  604. #endif
  605.     unit->aino_cache_size -= i;
  606.     }
  607. }
  608.  
  609. static void update_child_names (Unit *unit, struct a_inode *a, struct a_inode *parent)
  610. {
  611.     int l0 = strlen (parent->nname) + 2;
  612.  
  613.     while (a != 0) {
  614.     char *name_start;
  615.     char *new_name;
  616.  
  617.     a->parent = parent;
  618.     name_start = strrchr (a->nname, '/');
  619.     if (name_start == 0) {
  620.         write_log ("malformed file name");
  621.     }
  622.     name_start++;
  623.     new_name = malloc (strlen (name_start) + l0);
  624.     strcpy (new_name, parent->nname);
  625.     strcat (new_name, "/");
  626.     strcat (new_name, name_start);
  627.     free (a->nname);
  628.     a->nname = new_name;
  629.     if (a->child)
  630.         update_child_names (unit, a->child, a);
  631.     a = a->sibling;
  632.     }
  633. }
  634.  
  635. static void move_aino_children (Unit *unit, struct a_inode *from, struct a_inode *to)
  636. {
  637.     to->child = from->child;
  638.     from->child = 0;
  639.     update_child_names (unit, to->child, to);
  640. }
  641.  
  642. static void delete_aino (Unit *unit, struct a_inode *aino)
  643. {
  644.     struct a_inode **aip;
  645.     int hash;
  646.     
  647.     TRACE((warning_buffer, "deleting aino %x\n", aino->uniq));
  648.     
  649.     de_recycle_aino (unit, aino);
  650.     aip = &aino->parent->child;
  651.     while (*aip != aino && *aip != 0)
  652.     aip = &(*aip)->sibling;
  653.     if (*aip != aino) {
  654.     write_log ("Couldn't delete aino.\n");
  655.     return;
  656.     }
  657.     hash = aino->uniq % MAX_AINO_HASH;
  658.     if (unit->aino_hash[hash] == aino)
  659.         unit->aino_hash[hash] = 0;
  660.     *aip = aino->sibling;
  661.     free (aino->nname);
  662.     free (aino->aname);
  663.     free (aino);
  664. }
  665.  
  666. static struct a_inode *lookup_sub (struct a_inode *dir, uae_u32 uniq)
  667. {
  668.     struct a_inode **cp = &dir->child;
  669.     struct a_inode *c, *retval;
  670.  
  671.     for (;;) {
  672.     c = *cp;
  673.     if (c == 0)
  674.         return 0;
  675.  
  676.     if (c->uniq == uniq) {
  677.         retval = c;
  678.         break;
  679.     }
  680.     if (c->dir) {
  681.         struct a_inode *a = lookup_sub (c, uniq);
  682.         if (a != 0) {
  683.         retval = a;
  684.         break;
  685.         }
  686.     }
  687.     cp = &c->sibling;
  688.     }
  689.     *cp = c->sibling;
  690.     c->sibling = dir->child;
  691.     dir->child = c;
  692.     return retval;
  693. }
  694.  
  695. static struct a_inode *lookup_aino (Unit *unit, uae_u32 uniq)
  696. {
  697.     struct a_inode *a;
  698.     int hash = uniq % MAX_AINO_HASH;
  699.  
  700.     if (uniq == 0)
  701.     return &unit->rootnode;
  702.     a = unit->aino_hash[hash];
  703.     if (a == 0 || a->uniq != uniq)
  704.     a = lookup_sub (&unit->rootnode, uniq);
  705.     else
  706.     unit->nr_cache_hits++;
  707.     unit->nr_cache_lookups++;
  708.     unit->aino_hash[hash] = a;
  709.     return a;
  710. }
  711.  
  712. /* This gets called to translate an Amiga name that some program used to
  713.  * a name that we can use on the native filesystem. */
  714. static char *get_nname (Unit *unit, struct a_inode *base, char *rel)
  715. {
  716. #if 0
  717.     DIR* dir;
  718.     struct dirent* de;
  719.     char *p = 0;
  720.  
  721.     dir = opendir(base->nname);
  722.     if (dir) {
  723.     struct dirent de_space;
  724.     while((de = my_readdir (dir, &de_space))) {
  725.         if (strcasecmp(de->d_name, rel) == 0)
  726.         break;
  727.     }
  728.     if (de) {
  729.         p = malloc (strlen (de->d_name) + strlen (base->nname) + 2);
  730.         if (p != 0) {
  731.         strcpy (p, base->nname);
  732.         strcat (p, "/");
  733.         strcat (p, de->d_name);
  734.         }
  735.     }
  736.     closedir(dir);
  737.     }
  738.     return p;
  739. #endif
  740. }
  741.  
  742. /*
  743.  * This gets called if an ACTION_EXAMINE_NEXT happens and we hit an object
  744.  * for which we know the name on the native filesystem, but no corresponding
  745.  * Amiga filesystem name.
  746.  * @@@ For DOS filesystems, it might make sense to declare the new name 
  747.  * "weak", so that it can get overriden by a subsequent call to get_nname().
  748.  * That way, if someone does "dir :" and there is a file "foobar.inf", and
  749.  * someone else tries to open "foobar.info", get_nname() could maybe made to
  750.  * figure out that this is supposed to be the file "foobar.inf".
  751.  * DOS sucks...
  752.  */
  753. static char *get_aname (Unit *unit, struct a_inode *base, char *rel)
  754. {
  755.     char *p = 0;
  756.  
  757.     p = malloc (strlen (rel) + strlen (base->aname) + 2);
  758.     if (p != 0) {
  759.     strcpy (p, base->aname);
  760.     strcat (p, "/");
  761.     strcat (p, rel);
  762.     }
  763.     return p;
  764. }
  765.  
  766. static struct a_inode *new_child_aino (Unit *unit, struct a_inode *base, char *rel, int force)
  767. {
  768.     struct stat statbuf;
  769.     char *nn;
  770.     struct a_inode *aino;
  771.  
  772.     nn = get_nname (unit, base, rel);
  773.     if (nn == 0 && !force)
  774.     return 0;
  775.     else if (nn != 0)
  776.     force = 0;
  777.  
  778.     aino = malloc (sizeof (struct a_inode));
  779.     if (aino == 0)
  780.     return 0;
  781.     aino->aname = my_strdup (rel);
  782.     if (nn == 0) {
  783.     nn = malloc (strlen (base->nname) + strlen (rel) + 2);
  784.     strcpy (nn, base->nname);
  785.     strcat (nn, "/");
  786.     strcat (nn, rel);
  787.     free (rel);
  788.     }
  789.     aino->nname = nn;
  790.     aino->uniq = ++unit->a_uniq;
  791.     if (unit->a_uniq == 0xFFFFFFFF) {
  792.     write_log ("Running out of a_inodes (prepare for big trouble)!\n");
  793.     }
  794.     aino->shlock = 0;
  795.     aino->elock = 0;
  796.  
  797.     /* Update tree structure */
  798.     aino->parent = base;
  799.     aino->child = 0;
  800.     aino->sibling = base->child;
  801.     base->child = aino;
  802.     aino->next = aino->prev = 0;
  803.  
  804.     if (force == 2) {
  805.     aino->dir = 1;
  806.     aino->amigaos_mode = 0;
  807.     } else if (force == 1) {
  808.     aino->dir = 0;
  809.     aino->amigaos_mode = 0;
  810.     } else {
  811.     get_file_attrs (aino);
  812.     }
  813.     recycle_aino (unit, aino);
  814.     TRACE((warning_buffer, "created aino %x, normal\n", aino->uniq));
  815.     return aino;
  816. }
  817.  
  818. static struct a_inode *lookup_child_aino (Unit *unit, struct a_inode *base, char *rel, uae_u32 *err)
  819. {
  820.  #if 0
  821.     struct a_inode *c = base->child;
  822.     char *p, *p2;
  823.     int l0 = strlen (rel);
  824.  
  825.     if (base->dir == 0) {
  826.     *err = ERROR_OBJECT_WRONG_TYPE;
  827.     return 0;
  828.     }
  829.  
  830.     while (c != 0) {
  831.     int l1 = strlen (c->aname);
  832.     if (l0 <= l1 && strcasecmp (rel, c->aname + l1 - l0) == 0
  833.         && (l0 == l1 || c->aname[l1-l0-1] == '/'))
  834.         break;
  835.     c = c->sibling;
  836.     }
  837.     if (c != 0)
  838.     return c;
  839.     c = new_child_aino (unit, base, rel, 0);
  840.     if (c == 0)
  841.     *err = ERROR_OBJECT_NOT_FOUND;
  842.     return c;
  843. #endif
  844. }
  845.  
  846. /* Different version because this one compares with the nname */
  847. static struct a_inode *lookup_child_aino_for_exnext (Unit *unit, struct a_inode *base, char *rel, uae_u32 *err)
  848. {
  849.     struct a_inode *c = base->child;
  850.     char *p, *p2;
  851.     int l0 = strlen (rel);
  852.  
  853.     *err = 0;
  854.     while (c != 0) {
  855.     int l1 = strlen (c->nname);
  856.     if (l0 <= l1 && strcasecmp (rel, c->nname + l1 - l0) == 0
  857.         && (l0 == l1 || c->nname[l1-l0-1] == '/'))
  858.         break;
  859.     c = c->sibling;
  860.     }
  861.     if (c != 0)
  862.     return c;
  863.     c = malloc (sizeof (struct a_inode));
  864.     if (c == 0)
  865.     *err = ERROR_NO_FREE_STORE;
  866.     else {
  867.     c->nname = malloc (strlen (base->nname) + l0 + 2);
  868.     strcpy (c->nname, base->nname);
  869.     strcat (c->nname, "/");
  870.     strcat (c->nname, rel);
  871.     c->aname = get_aname (unit, base, rel);
  872.     c->uniq = ++unit->a_uniq;
  873.     if (unit->a_uniq == 0xFFFFFFFF) {
  874.         write_log ("Running out of a_inodes (prepare for big trouble)!\n");
  875.     }
  876.     c->shlock = 0;
  877.     c->elock = 0;
  878.  
  879.     /* Update tree structure */
  880.     c->parent = base;
  881.     c->child = 0;
  882.     c->sibling = base->child;
  883.     base->child = c;
  884.     c->next = c->prev = 0;
  885.  
  886.     get_file_attrs (c);
  887.     recycle_aino (unit, c);
  888.     TRACE((warning_buffer, "created aino %x, exnext\n", c->uniq));
  889.     }
  890.     return c;
  891. }
  892.  
  893. static struct a_inode *get_aino(Unit* unit, struct a_inode *base, const char *rel, uae_u32 *err)
  894. {
  895.     char *tmp;
  896.     char *p;
  897.     char *r;
  898.     struct a_inode *curr;
  899.     int i;
  900.  
  901.     *err = 0;
  902.     TRACE((warning_buffer, "get_path(%s,%s)\n", base->aname, rel));
  903.  
  904.     /* root-relative path? */
  905.     for(i = 0; rel[i] && rel[i] != '/' && rel[i] != ':'; i++)
  906.     ;
  907.     if (':' == rel[i])
  908.     rel += i+1;
  909.  
  910.     tmp = my_strdup (rel);
  911.     p = tmp;
  912.     curr = base;
  913.     
  914.     while(*p) {
  915.     /* start with a slash? go up a level. */
  916.     if (*p == '/') {
  917.         if (curr->parent != 0)
  918.         curr = curr->parent;
  919.         p++;
  920.     } else {
  921.         struct a_inode *next;
  922.         
  923.         char *component_end;
  924.         component_end = strchr (p, '/');
  925.         if (component_end != 0)
  926.         *component_end = '\0';
  927.         next = lookup_child_aino (unit, curr, p, err);
  928.         if (next == 0) {
  929.         /* if only last component not found, return parent dir. */
  930.         if (*err != ERROR_OBJECT_NOT_FOUND || component_end != 0)
  931.             curr = 0;
  932.         /* ? what error is appropriate? */
  933.         break;
  934.         }
  935.         curr = next;
  936.         if (component_end)
  937.         p = component_end+1;
  938.         else
  939.         break;
  940.         
  941.     }
  942.     }
  943.     free (tmp);
  944.     return curr;
  945. }
  946.  
  947. static uae_u32 startup_handler (void)
  948. {
  949.     /* Just got the startup packet. It's in A4. DosBase is in A2,
  950.      * our allocated volume structure is in D6, A5 is a pointer to
  951.      * our port. */
  952.     uaecptr rootnode = get_long(m68k_areg (regs, 2) + 34);
  953.     uaecptr dos_info = get_long(rootnode + 24) << 2;
  954.     uaecptr pkt = m68k_dreg (regs, 3);
  955.     uaecptr arg2 = get_long (pkt + dp_Arg2);
  956.     int i, namelen;
  957.     char* devname = bstr1 (get_long (pkt + dp_Arg1) << 2);
  958.     char* s;
  959.     Unit* unit;
  960.     UnitInfo *uinfo;
  961.  
  962.     /* find UnitInfo with correct device name */
  963.     s = strchr(devname, ':');
  964.     if(s)
  965.     *s = '\0';
  966.  
  967.     for(i = 0; i < num_units; i++) {
  968.     /* Hardfile volume name? */
  969.     if (ui[i].volname == 0)
  970.         continue;
  971.  
  972.     if (ui[i].startup == arg2)
  973.         break;        
  974.     }
  975.     
  976.     if(i == num_units || 0 != access(ui[i].rootdir, R_OK)) {
  977.     sprintf(warning_buffer, "Failed attempt to mount device\n", devname);
  978.     write_log (warning_buffer);
  979.     put_long (pkt + dp_Res1, DOS_FALSE);
  980.     put_long (pkt + dp_Res2, ERROR_DEVICE_NOT_MOUNTED);
  981.     return 1;
  982.     }
  983.     uinfo = ui + i;
  984.     
  985.     unit = (Unit *) malloc (sizeof (Unit));
  986.     unit->next = units;
  987.     units = unit;
  988.     uinfo->self = unit;
  989.  
  990.     unit->volume = 0;
  991.     unit->reset_state = FS_STARTUP;
  992.     unit->port = m68k_areg(regs, 5);
  993.     unit->unit = unit_num++;
  994.  
  995.     unit->ui.devname = uinfo->devname;
  996.     unit->ui.volname = my_strdup (uinfo->volname); /* might free later for rename */
  997.     unit->ui.rootdir = uinfo->rootdir;
  998.     unit->ui.readonly = uinfo->readonly;
  999.     unit->ui.unit_pipe = uinfo->unit_pipe;
  1000.     unit->ui.back_pipe = uinfo->back_pipe;
  1001.     unit->cmds_complete = 0;
  1002.     unit->cmds_sent = 0;
  1003.     unit->cmds_acked = 0;
  1004.     for (i = 0; i < EXKEYS; i++) {
  1005.     unit->examine_keys[i].aino = 0;
  1006.     unit->examine_keys[i].dir = 0;
  1007.     unit->examine_keys[i].uniq = 0;
  1008.     }
  1009.     unit->next_exkey = 1;
  1010.     unit->keys = 0;
  1011.     unit->a_uniq = unit->key_uniq = 0;
  1012.  
  1013.     unit->rootnode.aname = uinfo->volname;
  1014.     unit->rootnode.nname = uinfo->rootdir;
  1015.     unit->rootnode.sibling = 0;
  1016.     unit->rootnode.next = unit->rootnode.prev = &unit->rootnode;
  1017.     unit->rootnode.uniq = 0;
  1018.     unit->rootnode.parent = 0;
  1019.     unit->rootnode.child = 0;
  1020.     unit->rootnode.dir = 1;
  1021.     unit->rootnode.amigaos_mode = 0;
  1022.     unit->rootnode.shlock = 0;
  1023.     unit->rootnode.elock = 0;
  1024.     unit->aino_cache_size = 0;
  1025.     for (i = 0; i < MAX_AINO_HASH; i++)
  1026.     unit->aino_hash[i] = 0;
  1027.  
  1028. /*    write_comm_pipe_int (unit->ui.unit_pipe, -1, 1);*/
  1029.  
  1030.     TRACE((warning_buffer, "**** STARTUP volume %s\n", unit->ui.volname));
  1031.  
  1032.     /* fill in our process in the device node */
  1033.     put_long ((get_long (pkt + dp_Arg3) << 2) + 8, unit->port);
  1034.     unit->dosbase = m68k_areg(regs, 2);
  1035.  
  1036.     /* make new volume */
  1037.     unit->volume = m68k_areg (regs, 3) + 32;
  1038. #ifdef SUPPORT_THREADS
  1039.     unit->locklist = m68k_areg (regs, 3) + 8;
  1040. #else
  1041.     unit->locklist = m68k_areg (regs, 3);
  1042. #endif
  1043.     unit->dummy_message = m68k_areg (regs, 3) + 12;
  1044.  
  1045.     put_long (unit->dummy_message + 10, 0);
  1046.  
  1047.     put_long (unit->volume + 4, 2); /* Type = dt_volume */
  1048.     put_long (unit->volume + 12, 0); /* Lock */
  1049.     put_long (unit->volume + 16, 3800); /* Creation Date */
  1050.     put_long (unit->volume + 20, 0);
  1051.     put_long (unit->volume + 24, 0);
  1052.     put_long (unit->volume + 28, 0); /* lock list */
  1053.     put_long (unit->volume + 40, (unit->volume + 44) >> 2); /* Name */
  1054.     namelen = strlen (unit->ui.volname);
  1055.     put_byte (unit->volume + 44, namelen);
  1056.     for(i = 0; i < namelen; i++)
  1057.     put_byte (unit->volume + 45 + i, unit->ui.volname[i]);
  1058.     
  1059.     /* link into DOS list */
  1060.     put_long (unit->volume, get_long(dos_info + 4));
  1061.     put_long (dos_info + 4, unit->volume >> 2);
  1062.     
  1063.     put_long (unit->volume + 8, unit->port);
  1064.     put_long (unit->volume + 32, DISK_TYPE);
  1065.  
  1066.     put_long (pkt + dp_Res1, DOS_TRUE);
  1067.     return 0;
  1068. }
  1069.  
  1070. #ifdef HAVE_STATFS
  1071. static void
  1072. do_info(Unit* unit, dpacket packet, uaecptr info)
  1073. {
  1074.     struct statfs statbuf;
  1075. #if STATFS_NO_ARGS == 2
  1076.     if(-1 == statfs(unit->ui.rootdir, &statbuf))
  1077. #else
  1078.     if(-1 == statfs(unit->ui.rootdir, &statbuf, sizeof(struct statfs), 0))
  1079. #endif
  1080.     {
  1081.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1082.     PUT_PCK_RES2 (packet, dos_errno ());
  1083.     }
  1084.  
  1085.     put_long(info, 0); /* errors */
  1086.     put_long(info + 4, unit->unit); /* unit number */
  1087.     put_long(info + 8, unit->ui.readonly ? 80 : 82); /* state  */
  1088.     put_long(info + 12, statbuf.f_blocks); /* numblocks */
  1089.     put_long(info + 16, statbuf.f_blocks - statbuf.STATBUF_BAVAIL); /* inuse */
  1090.     put_long(info + 20, statbuf.f_bsize); /* bytesperblock */
  1091.     put_long(info + 24, DISK_TYPE); /* disk type */
  1092.     put_long(info + 28, unit->volume >> 2); /* volume node */
  1093.     put_long(info + 32, 0); /* inuse */
  1094.     PUT_PCK_RES1 (packet, DOS_TRUE);
  1095. }
  1096. #else
  1097. static void
  1098. do_info(Unit* unit, dpacket packet, uaecptr info)
  1099. {
  1100.     put_long(info, 0); /* errors */
  1101.     put_long(info + 4, unit->unit); /* unit number */
  1102.     put_long(info + 8, unit->ui.readonly ? 80 : 82); /* state  */
  1103.     put_long(info + 12, 256); /* numblocks */
  1104.     put_long(info + 16, 128); /* inuse */
  1105.     put_long(info + 20, 512); /* bytesperblock */
  1106.     put_long(info + 24, DISK_TYPE); /* disk type */
  1107.     put_long(info + 28, unit->volume >> 2); /* volume node */
  1108.     put_long(info + 32, 0); /* inuse */
  1109.     PUT_PCK_RES1 (packet, DOS_TRUE);
  1110. }
  1111. #endif
  1112.  
  1113. static void
  1114. action_disk_info(Unit* unit, dpacket packet)
  1115. {
  1116.     TRACE((warning_buffer, "ACTION_DISK_INFO\n"));
  1117.     do_info(unit, packet, GET_PCK_ARG1 (packet) << 2);
  1118. }
  1119.  
  1120. static void
  1121. action_info(Unit* unit, dpacket packet)
  1122. {
  1123.     TRACE((warning_buffer, "ACTION_INFO\n"));
  1124.     do_info(unit, packet, GET_PCK_ARG2 (packet) << 2);
  1125. }
  1126.  
  1127. static void free_key (Unit *unit, Key*k)
  1128. {
  1129.     Key *k1;
  1130.     Key *prev = 0;
  1131.     for (k1 = unit->keys; k1; k1 = k1->next) {
  1132.         if (k == k1) {
  1133.             if(prev)
  1134.                 prev->next = k->next;
  1135.             else
  1136.                 unit->keys = k->next;
  1137.             break;
  1138.         }
  1139.         prev = k1;
  1140.     }
  1141.  
  1142.     if (k->fd >= 0)
  1143.     close(k->fd);
  1144.  
  1145.     free(k);
  1146. }
  1147.  
  1148. static Key *lookup_key(Unit *unit, uae_u32 uniq)
  1149. {
  1150.     Key *k;
  1151.     /* It's hardly worthwhile to optimize this - most of the time there are
  1152.      * only one or zero keys. */
  1153.     for(k = unit->keys; k; k = k->next) {
  1154.         if (uniq == k->uniq)
  1155.             return k;
  1156.     }
  1157.     write_log ("Error: couldn't find key!\n");
  1158. #if 0
  1159.     exit(1);
  1160.     /* NOTREACHED */
  1161. #endif
  1162.     /* There isn't much hope we will recover. Unix would kill the process,
  1163.      * AmigaOS gets killed by it. */
  1164.     write_log ("Better reset that Amiga - the system is messed up.\n");
  1165.     return 0;
  1166. }
  1167.  
  1168. static Key *new_key(Unit *unit)
  1169. {
  1170.     Key *k = (Key*) malloc(sizeof(Key));
  1171.     k->uniq = ++unit->key_uniq;
  1172.     k->fd = -1;
  1173.     k->file_pos = 0;
  1174.     k->next = unit->keys;
  1175.     unit->keys = k;
  1176.  
  1177.     return k;
  1178. }
  1179.  
  1180. static void
  1181. dumplock(Unit *unit, uaecptr lock)
  1182. {
  1183.     struct a_inode *a;
  1184.     TRACE((warning_buffer, "LOCK: 0x%lx", lock));
  1185.     if(!lock) {
  1186.     TRACE((warning_buffer, "\n"));
  1187.     return;
  1188.     }
  1189.     TRACE((warning_buffer, "{ next=0x%lx, mode=%ld, handler=0x%lx, volume=0x%lx, aino %lx ",
  1190.        get_long(lock) << 2, get_long(lock+8), 
  1191.        get_long(lock+12), get_long(lock+16),
  1192.        get_long(lock + 4)));
  1193.     a = lookup_aino (unit, get_long (lock + 4));
  1194.     if (a == 0) {
  1195.     TRACE((warning_buffer, "not found!"));
  1196.     } else {
  1197.     TRACE((warning_buffer, "%s", a->nname));
  1198.     }
  1199.     TRACE((warning_buffer, " }\n"));
  1200. }
  1201.  
  1202. static struct a_inode *find_aino(Unit* unit, uaecptr lock, const char *name, uae_u32 *err)
  1203. {
  1204.     struct a_inode *a;
  1205.  
  1206.     if (lock) {
  1207.     struct a_inode *olda = lookup_aino (unit, get_long(lock + 4));
  1208.     if (olda == 0) {
  1209.         /* That's the best we can hope to do. */
  1210.         a = get_aino (unit, &unit->rootnode, name, err);
  1211.     } else {
  1212.         TRACE((warning_buffer, "aino: 0x%08lx", (unsigned long int)olda->uniq));
  1213.         TRACE((warning_buffer, " \"%s\"\n", olda->nname));
  1214.         a = get_aino (unit, olda, name, err);
  1215.     }
  1216.     } else {
  1217.     a = get_aino (unit, &unit->rootnode, name, err);
  1218.     }
  1219.     if (a) {
  1220.     TRACE((warning_buffer, "aino=\"%s\"\n", a->nname));
  1221.     }
  1222.     return a;
  1223. }
  1224.  
  1225. static uaecptr make_lock (Unit* unit, uae_u32 uniq, long mode)
  1226. {
  1227.     /* allocate lock from the list kept by the assembly code */
  1228.     uaecptr lock;
  1229.  
  1230.     lock = get_long (unit->locklist);
  1231.     put_long (unit->locklist, get_long (lock));
  1232.     lock += 4;
  1233.  
  1234.     put_long(lock + 4, uniq);
  1235.     put_long(lock + 8, mode);
  1236.     put_long(lock + 12, unit->port);
  1237.     put_long(lock + 16, unit->volume >> 2);
  1238.  
  1239.     /* prepend to lock chain */
  1240.     put_long(lock, get_long(unit->volume + 28));
  1241.     put_long(unit->volume + 28, lock >> 2);
  1242.  
  1243.     DUMPLOCK(unit, lock);
  1244.     return lock;
  1245. }
  1246.  
  1247. static void free_lock (Unit* unit, uaecptr lock)
  1248. {
  1249.     Key *k;
  1250.     if(!lock)
  1251.     return;
  1252.  
  1253.     if (lock == get_long(unit->volume + 28) << 2) {
  1254.     put_long(unit->volume + 28, get_long(lock));
  1255.     } else {
  1256.     uaecptr current = get_long(unit->volume + 28);
  1257.     uaecptr next = 0;
  1258.     while(current) {
  1259.         next = get_long(current << 2);
  1260.         if(lock == next << 2)
  1261.         break;
  1262.         current = next;
  1263.     }
  1264.     put_long(current << 2, get_long(lock));
  1265.     }
  1266.     lock -= 4;
  1267.     put_long (lock, get_long (unit->locklist));
  1268.     put_long (unit->locklist, lock);
  1269. }
  1270.  
  1271. static void
  1272. action_lock(Unit* unit, dpacket packet)
  1273. {
  1274.     uaecptr lock = GET_PCK_ARG1 (packet) << 2;
  1275.     uaecptr name = GET_PCK_ARG2 (packet) << 2;
  1276.     long mode = GET_PCK_ARG3 (packet);
  1277.     struct a_inode *a;
  1278.     uae_u32 err;
  1279.  
  1280.     if (mode != -2 && mode != -1) {
  1281.     TRACE((warning_buffer, "Bad mode.\n"));
  1282.     mode = -2;
  1283.     }
  1284.     
  1285.     TRACE((warning_buffer, "ACTION_LOCK(0x%lx, \"%s\", %d)\n", lock, bstr (unit, name), mode));
  1286.     DUMPLOCK(unit, lock);
  1287.     
  1288.     a = find_aino (unit, lock, bstr (unit, name), &err);
  1289.     if (err == 0 && (a->elock || (mode != -2 && a->shlock > 0))) {
  1290.     err = ERROR_OBJECT_IN_USE;
  1291.     }
  1292.     /* Lock() doesn't do access checks. */
  1293.     if (err != 0) {
  1294.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1295.     PUT_PCK_RES2 (packet, err);
  1296.     return;
  1297.     }
  1298.     if (mode == -2)
  1299.     a->shlock++;
  1300.     else
  1301.     a->elock = 1;
  1302.     de_recycle_aino (unit, a);
  1303.     PUT_PCK_RES1 (packet, make_lock (unit, a->uniq, mode) >> 2);
  1304. }
  1305.  
  1306. static void action_free_lock (Unit* unit, dpacket packet)
  1307. {
  1308.     uaecptr lock = GET_PCK_ARG1 (packet) << 2;
  1309.     struct a_inode *a;
  1310.     TRACE((warning_buffer, "ACTION_FREE_LOCK(0x%lx)\n", lock));
  1311.     DUMPLOCK(unit, lock);
  1312.  
  1313.     a = lookup_aino (unit, get_long (lock + 4));
  1314.     if (a == 0) {
  1315.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1316.     PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_FOUND);
  1317.     return;
  1318.     }
  1319.     if (a->elock)
  1320.     a->elock = 0;
  1321.     else
  1322.     a->shlock--;
  1323.     recycle_aino (unit, a);
  1324.     free_lock(unit, lock);
  1325.  
  1326.     PUT_PCK_RES1 (packet, DOS_TRUE);
  1327. }
  1328.  
  1329. static void
  1330. action_dup_lock(Unit* unit, dpacket packet)
  1331. {
  1332.     uaecptr lock = GET_PCK_ARG1 (packet) << 2;
  1333.     struct a_inode *a;
  1334.     TRACE((warning_buffer, "ACTION_DUP_LOCK(0x%lx)\n", lock));
  1335.     DUMPLOCK(unit, lock);
  1336.  
  1337.     if(!lock) {
  1338.     PUT_PCK_RES1 (packet, 0);
  1339.     return;
  1340.     }
  1341.     a = lookup_aino (unit, get_long (lock + 4));
  1342.     if (a == 0) {
  1343.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1344.     PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_FOUND);
  1345.     return;
  1346.     }
  1347.     /* DupLock()ing exclusive locks isn't possible, says the Autodoc, but
  1348.      * at least the RAM-Handler seems to allow it. Let's see what happens
  1349.      * if we don't. */
  1350.     if (a->elock) {
  1351.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1352.     PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
  1353.     return;
  1354.     }
  1355.     a->shlock++;
  1356.     de_recycle_aino (unit, a);
  1357.     PUT_PCK_RES1 (packet, make_lock (unit, a->uniq, -2) >> 2);
  1358. }
  1359.  
  1360. /* convert time_t to/from AmigaDOS time */
  1361. const int secs_per_day = 24 * 60 * 60;
  1362. const int diff = (8 * 365 + 2) * (24 * 60 * 60);
  1363.  
  1364. static void
  1365. get_time(time_t t, long* days, long* mins, long* ticks)
  1366. {
  1367.     /* time_t is secs since 1-1-1970 */
  1368.     /* days since 1-1-1978 */
  1369.     /* mins since midnight */
  1370.     /* ticks past minute @ 50Hz */
  1371.  
  1372.     t -= diff;
  1373.     *days = t / secs_per_day;
  1374.     t -= *days * secs_per_day;
  1375.     *mins = t / 60;
  1376.     t -= *mins * 60;
  1377.     *ticks = t * 50;
  1378. }
  1379.  
  1380. static time_t
  1381. put_time(long days, long mins, long ticks)
  1382. {
  1383.     time_t t;
  1384.     t = ticks / 50;
  1385.     t += mins * 60;
  1386.     t += days * secs_per_day;
  1387.     t += diff;
  1388.  
  1389.     return t;
  1390. }
  1391.  
  1392. static void free_exkey(ExamineKey* ek)
  1393. {
  1394.     ek->aino = 0;
  1395.     ek->uniq = 0;
  1396. //    if (ek->dir)
  1397. //    closedir (ek->dir);
  1398. }
  1399.  
  1400. /* This is so sick... who invented ACTION_EXAMINE_NEXT? What did he THINK??? */
  1401. static ExamineKey *new_exkey(Unit *unit, struct a_inode *aino)
  1402. {
  1403.     uae_u32 uniq;
  1404.     uae_u32 oldest = 0xFFFFFFFF;
  1405.     ExamineKey *ek, *oldest_ek = 0;
  1406.     int i;
  1407.     
  1408.     ek = unit->examine_keys;
  1409.     for (i = 0; i < EXKEYS; i++, ek++) {
  1410.     /* Did we find a free one? */
  1411.     if (ek->aino == 0)
  1412.         continue;
  1413.     if (ek->uniq < oldest)
  1414.         oldest = (oldest_ek = ek)->uniq;
  1415.     }
  1416.     ek = unit->examine_keys;
  1417.     for (i = 0; i < EXKEYS; i++, ek++) {
  1418.     /* Did we find a free one? */
  1419.     if (ek->aino == 0)
  1420.         goto found;
  1421.     }
  1422.     /* This message should usually be harmless. */
  1423.     write_log ("Houston, we have a problem.\n");
  1424.     free_exkey (oldest_ek);
  1425.     ek = oldest_ek;
  1426.     found:
  1427.  
  1428.     uniq = unit->next_exkey;
  1429.     if (uniq == 0xFFFFFFFF) {
  1430.     /* Things will probably go wrong, but most likely the Amiga will crash
  1431.      * before this happens because of something else. */
  1432.     uniq = 1;
  1433.     }
  1434.     unit->next_exkey = uniq+1;
  1435.     ek->aino = aino;
  1436.     ek->dir = 0;
  1437.     ek->uniq = uniq;
  1438.     return ek;
  1439. }
  1440.  
  1441. static ExamineKey *lookup_exkey(Unit *unit, uae_u32 uniq)
  1442. {
  1443.     ExamineKey *ek;
  1444.     int i;
  1445.  
  1446.     ek = unit->examine_keys;
  1447.     for (i = 0; i < EXKEYS; i++, ek++) {
  1448.     /* Did we find a free one? */
  1449.     if (ek->uniq == uniq)
  1450.         return ek;
  1451.     }
  1452.     write_log ("Houston, we have a BIG problem.\n");
  1453.     return 0;
  1454. }
  1455.  
  1456. static void
  1457. get_fileinfo(Unit *unit, dpacket packet, uaecptr info, struct a_inode *aino)
  1458. {
  1459.     struct stat statbuf;
  1460.     long days, mins, ticks;
  1461.     int i, n;
  1462.     char *x;
  1463.     uae_u32 err;
  1464.     
  1465.     /* No error checks - this had better work. */
  1466.     stat (aino->nname, &statbuf);
  1467.  
  1468.     if (aino->parent == 0) {
  1469.     x = unit->ui.volname;
  1470.     put_long (info + 4, 1);
  1471.     put_long (info + 120, 1);
  1472.     } else {
  1473.     /* AmigaOS docs say these have to contain the same value. */
  1474.     put_long(info + 4, aino->dir ? 2 : -3);
  1475.     put_long(info + 120, aino->dir ? 2 : -3);
  1476.     x = strrchr (aino->aname, '/');
  1477.     if (x)
  1478.         x++;
  1479.     else
  1480.         x = aino->aname;
  1481.     }
  1482.     TRACE((warning_buffer, "name=\"%s\"\n", x));
  1483.     n = strlen(x);
  1484.     if (n > 106)
  1485.     n = 106;
  1486.     i = 8;
  1487.     put_byte(info + i, n); i++;
  1488.     while(n--)
  1489.     put_byte(info + i, *x), i++, x++;
  1490.     while(i < 108)
  1491.     put_byte(info + i, 0), i++;
  1492.  
  1493.     put_long (info + 116, aino->amigaos_mode);
  1494.     put_long(info + 124, statbuf.st_size);
  1495. #ifdef HAVE_ST_BLOCKS
  1496.     put_long(info + 128, statbuf.st_blocks);
  1497. #else
  1498.     put_long(info + 128, statbuf.st_size / 512 + 1);
  1499. #endif
  1500.     get_time(statbuf.st_mtime, &days, &mins, &ticks);
  1501.     put_long(info + 132, days);
  1502.     put_long(info + 136, mins);
  1503.     put_long(info + 140, ticks);
  1504.     put_long(info + 144, 0); /* no comment */
  1505.     PUT_PCK_RES1 (packet, DOS_TRUE);
  1506. }
  1507.  
  1508. static void do_examine(Unit *unit, dpacket packet, ExamineKey* ek, uaecptr info)
  1509. {
  1510. #if 0
  1511.     struct dirent de_space;
  1512.     struct dirent* de;
  1513.     struct a_inode *aino;
  1514.     uae_u32 err;
  1515.  
  1516.     if (!ek->dir) {
  1517.     ek->dir = opendir (ek->aino->nname);
  1518.     }
  1519.     if (!ek->dir) {
  1520.     free_exkey (ek);
  1521.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1522.     PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES);
  1523.     return;
  1524.     }
  1525.  
  1526.     de = my_readdir (ek->dir, &de_space);
  1527.  
  1528.     while (de && (0 == strcmp(".", de->d_name) 
  1529.          || 0 == strcmp("..", de->d_name)))
  1530.     {
  1531.     de = my_readdir (ek->dir, &de_space);
  1532.     }
  1533.  
  1534.     if (!de) {
  1535.     TRACE((warning_buffer, "no more entries\n"));
  1536.     free_exkey (ek);
  1537.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1538.     PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES);
  1539.     return;
  1540.     }
  1541.  
  1542.     TRACE((warning_buffer, "entry=\"%s\"\n", de->d_name));
  1543.     aino = lookup_child_aino_for_exnext (unit, ek->aino, de->d_name, &err);
  1544.     if (err != 0) {
  1545.     write_log ("Severe problem in ExNext.\n");
  1546.     free_exkey (ek);
  1547.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1548.     PUT_PCK_RES2 (packet, err);
  1549.     }
  1550.     get_fileinfo (unit, packet, info, aino);
  1551. #endif
  1552. }
  1553.  
  1554. static void action_examine_object (Unit* unit, dpacket packet)
  1555. {
  1556.     uaecptr lock = GET_PCK_ARG1 (packet) << 2;
  1557.     uaecptr info = GET_PCK_ARG2 (packet) << 2;
  1558.     ExamineKey* ek;
  1559.     struct a_inode *aino = 0;
  1560.  
  1561.     TRACE((warning_buffer, "ACTION_EXAMINE_OBJECT(0x%lx,0x%lx)\n", lock, info));
  1562.     DUMPLOCK(unit, lock);
  1563.  
  1564.     if (lock != 0)
  1565.     aino = lookup_aino (unit, get_long(lock + 4));
  1566.     if (aino == 0)
  1567.     aino = &unit->rootnode;
  1568.  
  1569.     get_fileinfo (unit, packet, info, aino);
  1570.     if (aino->dir) {
  1571.     put_long(info, 0xFFFFFFFF);
  1572.     } else
  1573.     put_long(info, 0);
  1574. }
  1575.  
  1576. static void action_examine_next(Unit* unit, dpacket packet)
  1577. {
  1578.     uaecptr lock = GET_PCK_ARG1 (packet) << 2;
  1579.     uaecptr info = GET_PCK_ARG2 (packet) << 2;
  1580.     struct a_inode *aino = 0;
  1581.     ExamineKey *ek;
  1582.     uae_u32 uniq;
  1583.  
  1584.     TRACE((warning_buffer, "ACTION_EXAMINE_NEXT(0x%lx,0x%lx)\n", lock, info));
  1585.     DUMPLOCK(unit, lock);
  1586.  
  1587.     if (lock != 0)
  1588.     aino = lookup_aino (unit, get_long(lock + 4));
  1589.     if (aino == 0)
  1590.     aino = &unit->rootnode;
  1591.  
  1592.     uniq = get_long (info);
  1593.     if (uniq == 0) {
  1594.     write_log ("ExNext called for a file! (Houston?)\n");
  1595.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1596.     PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES);
  1597.     return;
  1598.     } else if (uniq == 0xFFFFFFFF) {
  1599.     ek = new_exkey(unit, aino);
  1600.     } else
  1601.     ek = lookup_exkey (unit, get_long(info));
  1602.     if (ek == 0) {
  1603.     write_log ("Couldn't find a matching ExKey. Prepare for trouble.\n");
  1604.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1605.     PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES);
  1606.     return;
  1607.     }
  1608.     put_long(info, ek->uniq);
  1609.     do_examine(unit, packet, ek, info);
  1610. }
  1611.  
  1612. static void do_find (Unit* unit, dpacket packet, int mode, int create, int fallback)
  1613. {
  1614.  #if 0
  1615.     uaecptr fh = GET_PCK_ARG1 (packet) << 2;
  1616.     uaecptr lock = GET_PCK_ARG2 (packet) << 2;
  1617.     uaecptr name = GET_PCK_ARG3 (packet) << 2;
  1618.     struct a_inode *aino;
  1619.     Key *k;
  1620.     struct stat st;
  1621.     int fd;
  1622.     int doserr;
  1623.     uae_u32 err;
  1624.     mode_t openmode;
  1625.     int aino_created = 0;
  1626.  
  1627.     TRACE((warning_buffer, "ACTION_FIND_*(0x%lx,0x%lx,\"%s\",%d)\n", fh, lock, bstr (unit, name), mode));
  1628.     DUMPLOCK(unit, lock);
  1629.  
  1630.     aino = find_aino (unit, lock, bstr (unit, name), &err);
  1631.     
  1632.     if (aino == 0 || (err != 0 && err != ERROR_OBJECT_NOT_FOUND)) {
  1633.     /* Whatever it is, we can't handle it. */
  1634.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1635.     PUT_PCK_RES2 (packet, err);
  1636.     return;
  1637.     }
  1638.     if (err == 0) {
  1639.     /* Object exists. */
  1640.     if (aino->dir) {
  1641.         PUT_PCK_RES1 (packet, DOS_FALSE);
  1642.         PUT_PCK_RES2 (packet, ERROR_OBJECT_WRONG_TYPE);
  1643.         return;
  1644.     }
  1645.     if (aino->elock || (create == 2 && aino->shlock > 0)) {
  1646.         PUT_PCK_RES1 (packet, DOS_FALSE);
  1647.         PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
  1648.         return;
  1649.     }
  1650.     if (create == 2 && (aino->amigaos_mode & A_FIBF_DELETE) != 0) {
  1651.         PUT_PCK_RES1 (packet, DOS_FALSE);
  1652.         PUT_PCK_RES2 (packet, ERROR_DELETE_PROTECTED);
  1653.         return;
  1654.     }
  1655.     if (create != 2) {
  1656.         if ((((mode & aino->amigaos_mode) & A_FIBF_WRITE) != 0 || unit->ui.readonly)
  1657.         && fallback)
  1658.         {
  1659.         mode &= ~A_FIBF_WRITE;
  1660.         }
  1661.         /* Kick 1.3 doesn't check read and write access bits - maybe it would be
  1662.          * simpler just not to do that either. */
  1663.         if ((mode & A_FIBF_WRITE) != 0 && unit->ui.readonly) {
  1664.         PUT_PCK_RES1 (packet, DOS_FALSE);
  1665.         PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
  1666.         return;
  1667.         }
  1668.         if (((mode & aino->amigaos_mode) & A_FIBF_WRITE) != 0
  1669.         || mode == 0)
  1670.         {
  1671.         PUT_PCK_RES1 (packet, DOS_FALSE);
  1672.         PUT_PCK_RES2 (packet, ERROR_WRITE_PROTECTED);
  1673.         return;
  1674.         }
  1675.         if (((mode & aino->amigaos_mode) & A_FIBF_READ) != 0) {
  1676.         PUT_PCK_RES1 (packet, DOS_FALSE);
  1677.         PUT_PCK_RES2 (packet, ERROR_READ_PROTECTED);
  1678.         return;
  1679.         }
  1680.     }
  1681.     } else if (create == 0) {
  1682.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1683.     PUT_PCK_RES2 (packet, err);
  1684.     return;
  1685.     } else {
  1686.     aino_created = 1;
  1687.     /* Object does not exist. aino points to containing directory. */
  1688.     aino = new_child_aino (unit, aino, my_strdup (bstr_cut (unit, name)), 1);
  1689.     if (aino == 0) {
  1690.         PUT_PCK_RES1 (packet, DOS_FALSE);
  1691.         PUT_PCK_RES2 (packet, ERROR_DISK_FULL); /* best we can do */
  1692.         return;
  1693.     }
  1694.     }
  1695.  
  1696.     prepare_for_open (aino->nname);
  1697.  
  1698.     openmode = (((mode & A_FIBF_READ) == 0 ? O_WRONLY
  1699.          : (mode & A_FIBF_WRITE) == 0 ? O_RDONLY
  1700.          : O_RDWR)
  1701.         | (create ? O_CREAT : 0)
  1702.         | (create == 2 ? O_TRUNC : 0));
  1703.  
  1704.     fd = open (aino->nname, openmode | O_BINARY, 0777);
  1705.  
  1706.     if (fd < 0) {
  1707.     if (aino_created)
  1708.         delete_aino (unit, aino);
  1709.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1710.     PUT_PCK_RES2 (packet, dos_errno());
  1711.     return;
  1712.     }
  1713.     k = new_key (unit);
  1714.     k->fd = fd;
  1715.     k->aino = aino;
  1716.  
  1717.     put_long (fh+36, k->uniq);
  1718.     if (create == 2)
  1719.     aino->elock = 1;
  1720.     else
  1721.     aino->shlock++;
  1722.     de_recycle_aino (unit, aino);
  1723.     PUT_PCK_RES1 (packet, DOS_TRUE);
  1724. #endif
  1725. }
  1726.  
  1727. static void
  1728. action_find_input(Unit* unit, dpacket packet)
  1729. {
  1730.     do_find(unit, packet, A_FIBF_READ|A_FIBF_WRITE, 0, 1);
  1731. }
  1732.  
  1733. static void
  1734. action_find_output(Unit* unit, dpacket packet)
  1735. {
  1736.     if (unit->ui.readonly) {
  1737.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1738.     PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
  1739.     return;
  1740.     }
  1741.     do_find(unit, packet, A_FIBF_READ|A_FIBF_WRITE, 2, 0);
  1742. }
  1743.  
  1744. static void
  1745. action_find_write(Unit* unit, dpacket packet)
  1746. {
  1747.     if (unit->ui.readonly) {
  1748.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1749.     PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
  1750.     return;
  1751.     }
  1752.     do_find(unit, packet, A_FIBF_READ|A_FIBF_WRITE, 1, 0);
  1753. }
  1754.  
  1755. static void
  1756. action_end(Unit* unit, dpacket packet)
  1757. {
  1758.     Key *k;
  1759.     TRACE((warning_buffer, "ACTION_END(0x%lx)\n", GET_PCK_ARG1 (packet)));
  1760.  
  1761.     k = lookup_key (unit, GET_PCK_ARG1 (packet));
  1762.     if (k != 0) {
  1763.     if (k->aino->elock)
  1764.         k->aino->elock = 0;
  1765.     else
  1766.         k->aino->shlock--;
  1767.     recycle_aino (unit, k->aino);
  1768.     free_key (unit, k);
  1769.     }
  1770.     PUT_PCK_RES1 (packet, DOS_TRUE);
  1771.     PUT_PCK_RES2 (packet, 0);
  1772. }
  1773.  
  1774. static void
  1775. action_read(Unit* unit, dpacket packet)
  1776. {
  1777.  #if 0
  1778.     Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
  1779.     uaecptr addr = GET_PCK_ARG2 (packet);
  1780.     long size = (uae_s32)GET_PCK_ARG3 (packet);
  1781.     int actual;
  1782.  
  1783.     if (k == 0) {
  1784.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1785.     /* PUT_PCK_RES2 (packet, EINVAL); */
  1786.     return;
  1787.     }
  1788.     TRACE((warning_buffer, "ACTION_READ(%s,0x%lx,%ld)\n",k->aino->nname,addr,size));
  1789. #ifdef RELY_ON_LOADSEG_DETECTION
  1790.     /* HACK HACK HACK HACK 
  1791.      * Try to detect a LoadSeg() */
  1792.     if (k->file_pos == 0 && size >= 4) {
  1793.     unsigned char buf[4];
  1794.     off_t currpos = lseek(k->fd, 0, SEEK_CUR);
  1795.     read(k->fd, buf, 4);
  1796.     lseek(k->fd, currpos, SEEK_SET);
  1797.     if (buf[0] == 0 && buf[1] == 0 && buf[2] == 3 && buf[3] == 0xF3)
  1798.         possible_loadseg();
  1799.     }
  1800. #endif
  1801.     if (valid_address (addr, size)) {
  1802.     uae_u8 *realpt;
  1803.     realpt = get_real_address (addr);
  1804.     actual = read(k->fd, realpt, size);
  1805.  
  1806.     if (actual == 0) {
  1807.         PUT_PCK_RES1 (packet, 0);
  1808.         PUT_PCK_RES2 (packet, 0);
  1809.     } else if (actual < 0) {
  1810.         PUT_PCK_RES1 (packet, 0);
  1811.         PUT_PCK_RES2 (packet, dos_errno());
  1812.     } else {
  1813.         PUT_PCK_RES1 (packet, actual);
  1814.         k->file_pos += actual;
  1815.     }
  1816.     } else {
  1817.     char *buf;
  1818.     sprintf (warning_buffer, "unixfs warning: Bad pointer passed for read: %08x\n", addr);
  1819.     write_log (warning_buffer);
  1820.     /* ugh this is inefficient but easy */
  1821.     buf = (char *)malloc(size);
  1822.     if(!buf) {
  1823.         PUT_PCK_RES1 (packet, -1);
  1824.         PUT_PCK_RES2 (packet, ERROR_NO_FREE_STORE);
  1825.         return;
  1826.     }
  1827.     actual = read(k->fd, buf, size);
  1828.  
  1829.     if (actual < 0) {
  1830.         PUT_PCK_RES1 (packet, 0);
  1831.         PUT_PCK_RES2 (packet, dos_errno());
  1832.     } else {
  1833.         int i;
  1834.         PUT_PCK_RES1 (packet, actual);
  1835.         for(i = 0; i < actual; i++)
  1836.         put_byte(addr + i, buf[i]);
  1837.         k->file_pos += actual;
  1838.     }
  1839.     free(buf);
  1840.     }
  1841. #endif
  1842. }
  1843.  
  1844. static void
  1845. action_write(Unit* unit, dpacket packet)
  1846. {
  1847.     Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
  1848.     uaecptr addr = GET_PCK_ARG2 (packet);
  1849.     long size = GET_PCK_ARG3 (packet);
  1850.     char *buf;
  1851.     int i;
  1852.  
  1853.     if (k == 0) {
  1854.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1855.     /* PUT_PCK_RES2 (packet, EINVAL); */
  1856.     return;
  1857.     }
  1858.  
  1859.     TRACE((warning_buffer, "ACTION_WRITE(%s,0x%lx,%ld)\n",k->aino->nname,addr,size));
  1860.  
  1861.     if(unit->ui.readonly) {
  1862.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1863.     PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
  1864.     return;
  1865.     }
  1866.  
  1867.     /* ugh this is inefficient but easy */
  1868.     buf = (char *)malloc(size);
  1869.     if(!buf) {
  1870.     PUT_PCK_RES1 (packet, -1);
  1871.     PUT_PCK_RES2 (packet, ERROR_NO_FREE_STORE);
  1872.     return;
  1873.     }
  1874.  
  1875.     for(i = 0; i < size; i++)
  1876.     buf[i] = get_byte(addr + i);
  1877.  
  1878.     PUT_PCK_RES1 (packet, write(k->fd, buf, size));
  1879.     if (GET_PCK_RES1 (packet) != size)
  1880.     PUT_PCK_RES2 (packet, dos_errno());
  1881.     if (GET_PCK_RES1 (packet) >= 0)
  1882.     k->file_pos += GET_PCK_RES1 (packet);
  1883.  
  1884.     free(buf);
  1885. }
  1886.  
  1887. static void
  1888. action_seek(Unit* unit, dpacket packet)
  1889. {
  1890.     Key* k = lookup_key (unit, GET_PCK_ARG1 (packet));
  1891.     long pos = (uae_s32)GET_PCK_ARG2 (packet);
  1892.     long mode = (uae_s32)GET_PCK_ARG3 (packet);
  1893.     off_t res;
  1894.     long old;
  1895.     int whence = SEEK_CUR;
  1896.  
  1897.     if (k == 0) {
  1898.     PUT_PCK_RES1 (packet, -1);
  1899.     PUT_PCK_RES2 (packet, ERROR_INVALID_LOCK);
  1900.     return;
  1901.     }
  1902.  
  1903.     if(mode > 0) whence = SEEK_END;
  1904.     if(mode < 0) whence = SEEK_SET;
  1905.  
  1906.     TRACE((warning_buffer, "ACTION_SEEK(%s,%d,%d)\n",k->aino->nname,pos,mode));
  1907.  
  1908.     old = lseek(k->fd, 0, SEEK_CUR);
  1909.     res = lseek(k->fd, pos, whence);
  1910.  
  1911.     if(-1 == res) {
  1912.     PUT_PCK_RES1 (packet, res);
  1913.     PUT_PCK_RES2 (packet, ERROR_SEEK_ERROR);
  1914.     } else
  1915.     PUT_PCK_RES1 (packet, old);
  1916.     k->file_pos = res;
  1917. }
  1918.  
  1919. static void
  1920. action_set_protect(Unit* unit, dpacket packet)
  1921. {
  1922.     uaecptr lock = GET_PCK_ARG2 (packet) << 2;
  1923.     uaecptr name = GET_PCK_ARG3 (packet) << 2;
  1924.     uae_u32 mask = GET_PCK_ARG4 (packet);
  1925.     mode_t mode;
  1926.     struct a_inode *a;
  1927.     uae_u32 err;
  1928.  
  1929.     TRACE((warning_buffer, "ACTION_SET_PROTECT(0x%lx,\"%s\",0x%lx)\n", lock, bstr (unit, name), mask));
  1930.  
  1931.     if(unit->ui.readonly) {
  1932.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1933.     PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
  1934.     return;
  1935.     }
  1936.  
  1937.     a = find_aino (unit, lock, bstr (unit, name), &err);
  1938.     if (err != 0) {
  1939.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1940.     PUT_PCK_RES2 (packet, err);
  1941.     return;
  1942.     }
  1943.  
  1944.     err = set_file_attrs (a, mask);
  1945.     if (err != 0) {
  1946.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1947.     PUT_PCK_RES2 (packet, err);
  1948.     } else {
  1949.     PUT_PCK_RES1 (packet, DOS_TRUE);
  1950.     }
  1951. }
  1952.  
  1953. static void
  1954. action_same_lock(Unit* unit, dpacket packet)
  1955. {
  1956.     uaecptr lock1 = GET_PCK_ARG1 (packet) << 2;
  1957.     uaecptr lock2 = GET_PCK_ARG2 (packet) << 2;
  1958.  
  1959.     TRACE((warning_buffer, "ACTION_SAME_LOCK(0x%lx,0x%lx)\n",lock1,lock2));
  1960.     DUMPLOCK(unit, lock1); DUMPLOCK(unit, lock2);
  1961.  
  1962.     if(!lock1 || !lock2) {
  1963.     PUT_PCK_RES1 (packet, lock1 == lock2 ? DOS_TRUE : DOS_FALSE);
  1964.     } else {
  1965.     PUT_PCK_RES1 (packet, get_long (lock1 + 4) == get_long (lock2 + 4) ? DOS_TRUE : DOS_FALSE);
  1966.     }
  1967. }
  1968.  
  1969. static void
  1970. action_parent(Unit* unit, dpacket packet)
  1971. {
  1972.     uaecptr lock = GET_PCK_ARG1 (packet) << 2;
  1973.     struct a_inode *a, *olda;
  1974.  
  1975.     TRACE((warning_buffer, "ACTION_PARENT(0x%lx)\n",lock));
  1976.  
  1977.     if (!lock) {
  1978.     PUT_PCK_RES1 (packet, 0);
  1979.     PUT_PCK_RES2 (packet, 0);
  1980.     return;
  1981.     }
  1982.  
  1983.     olda = lookup_aino (unit, get_long(lock + 4));
  1984.     if (olda == 0) {
  1985.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1986.     PUT_PCK_RES2 (packet, ERROR_INVALID_LOCK);
  1987.     return;
  1988.     }
  1989.  
  1990.     if (olda->parent == 0) {
  1991.     PUT_PCK_RES1 (packet, 0);
  1992.     PUT_PCK_RES2 (packet, 0);
  1993.     return;
  1994.     }
  1995.     if (olda->parent->elock) {
  1996.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1997.     PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
  1998.     return;
  1999.     }
  2000.     olda->parent->shlock++;
  2001.     de_recycle_aino (unit, olda->parent);
  2002.     PUT_PCK_RES1 (packet, make_lock (unit, olda->parent->uniq, -2) >> 2);
  2003. }
  2004.  
  2005. static void
  2006. action_create_dir(Unit* unit, dpacket packet)
  2007. {
  2008.     uaecptr lock = GET_PCK_ARG1 (packet) << 2;
  2009.     uaecptr name = GET_PCK_ARG2 (packet) << 2;
  2010.     struct a_inode *aino;
  2011.     uae_u32 err;
  2012.  
  2013.     TRACE((warning_buffer, "ACTION_CREATE_DIR(0x%lx,\"%s\")\n", lock, bstr (unit, name)));
  2014.  
  2015.     if(unit->ui.readonly) {
  2016.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2017.     PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
  2018.     return;
  2019.     }
  2020.  
  2021.     aino = find_aino (unit, lock, bstr (unit, name), &err);
  2022.     if (aino == 0 || (err != 0 && err != ERROR_OBJECT_NOT_FOUND)) {
  2023.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2024.     PUT_PCK_RES2 (packet, err);
  2025.     return;
  2026.     }
  2027.     if (err == 0) {
  2028.     /* Object exists. */
  2029.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2030.     PUT_PCK_RES2 (packet, ERROR_OBJECT_EXISTS);
  2031.     return;
  2032.     }
  2033.     /* Object does not exist. aino points to containing directory. */
  2034.     aino = new_child_aino (unit, aino, my_strdup (bstr_cut (unit, name)), 2);
  2035.     if (aino == 0) {
  2036.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2037.     PUT_PCK_RES2 (packet, ERROR_DISK_FULL); /* best we can do */
  2038.     return;
  2039.     }
  2040.  
  2041.     if (mkdir (aino->nname, 0777) == -1) {
  2042.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2043.     PUT_PCK_RES2 (packet, dos_errno());
  2044.     return;
  2045.     }
  2046.     aino->shlock = 1;
  2047.     de_recycle_aino (unit, aino);
  2048.     PUT_PCK_RES1 (packet, make_lock (unit, aino->uniq, -2) >> 2);
  2049. }
  2050.  
  2051. static void
  2052. action_delete_object(Unit* unit, dpacket packet)
  2053. {
  2054.     uaecptr lock = GET_PCK_ARG1 (packet) << 2;
  2055.     uaecptr name = GET_PCK_ARG2 (packet) << 2;
  2056.     struct a_inode *a;
  2057.     uae_u32 err;
  2058.     
  2059.     TRACE((warning_buffer, "ACTION_DELETE_OBJECT(0x%lx,\"%s\")\n", lock, bstr (unit, name)));
  2060.  
  2061.     if (unit->ui.readonly) {
  2062.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2063.     PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
  2064.     return;
  2065.     }
  2066.  
  2067.     a = find_aino (unit, lock, bstr (unit, name), &err);
  2068.  
  2069.     if (err != 0) {
  2070.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2071.     PUT_PCK_RES2 (packet, err);
  2072.     return;
  2073.     }
  2074.     if (a->shlock > 0 || a->elock) {
  2075.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2076.     PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
  2077.     return;
  2078.     }
  2079.     if (a->dir) {
  2080.     if (rmdir (a->nname) == -1) {
  2081.         PUT_PCK_RES1 (packet, DOS_FALSE);
  2082.         PUT_PCK_RES2 (packet, dos_errno());
  2083.         return;
  2084.     }
  2085.     } else {
  2086.     if (unlink (a->nname) == -1) {
  2087.         PUT_PCK_RES1 (packet, DOS_FALSE);
  2088.         PUT_PCK_RES2 (packet, dos_errno());
  2089.         return;
  2090.     }
  2091.     }
  2092.     if (a->child != 0) {
  2093.     write_log ("Serious error in action_delete_object.\n");
  2094.     } else {
  2095.     delete_aino (unit, a);
  2096.     }
  2097.     PUT_PCK_RES1 (packet, DOS_TRUE);
  2098. }
  2099.  
  2100. static void
  2101. action_set_date(Unit* unit, dpacket packet)
  2102. {
  2103.     uaecptr lock = GET_PCK_ARG2 (packet) << 2;
  2104.     uaecptr name = GET_PCK_ARG3 (packet) << 2;
  2105.     uaecptr date = GET_PCK_ARG4 (packet);
  2106.     struct a_inode *a;
  2107.     struct utimbuf ut;
  2108.     uae_u32 err;
  2109.  
  2110.     TRACE((warning_buffer, "ACTION_SET_DATE(0x%lx,\"%s\")\n", lock, bstr (unit, name)));
  2111.  
  2112.     if(unit->ui.readonly) {
  2113.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2114.     PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
  2115.     return;
  2116.     }
  2117.  
  2118.     ut.actime = ut.modtime = put_time(get_long(date),get_long(date+4),get_long(date+8));
  2119.     a = find_aino (unit, lock, bstr (unit, name), &err);
  2120.     if (err == 0 && utime (a->nname, &ut) == -1)
  2121.     err = dos_errno ();
  2122.     if (err != 0) {
  2123.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2124.     PUT_PCK_RES2 (packet, err);
  2125.     } else
  2126.     PUT_PCK_RES1 (packet, DOS_TRUE);
  2127. }
  2128.  
  2129. static void
  2130. action_rename_object(Unit* unit, dpacket packet)
  2131. {
  2132.     uaecptr lock1 = GET_PCK_ARG1 (packet) << 2;
  2133.     uaecptr name1 = GET_PCK_ARG2 (packet) << 2;
  2134.     uaecptr lock2 = GET_PCK_ARG3 (packet) << 2;
  2135.     uaecptr name2 = GET_PCK_ARG4 (packet) << 2;
  2136.     struct a_inode *a1, *a2;
  2137.     uae_u32 err1, err2;
  2138.  
  2139.     TRACE((warning_buffer, "ACTION_RENAME_OBJECT(0x%lx,\"%s\",", lock1, bstr (unit, name1)));
  2140.     TRACE((warning_buffer, "0x%lx,\"%s\")\n", lock2, bstr (unit, name2)));
  2141.  
  2142.     if(unit->ui.readonly) {
  2143.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2144.     PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
  2145.     return;
  2146.     }
  2147.  
  2148.     a1 = find_aino (unit, lock1, bstr (unit, name1), &err1);
  2149.     if (err1 != 0) {
  2150.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2151.     PUT_PCK_RES2 (packet, err1);
  2152.     return;
  2153.     }
  2154.     a2 = find_aino (unit, lock2, bstr (unit, name2), &err2);
  2155.     if (a2 == 0 || err2 != ERROR_OBJECT_NOT_FOUND) {
  2156.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2157.     PUT_PCK_RES2 (packet, err2 == 0 ? ERROR_OBJECT_EXISTS : err2);
  2158.     return;
  2159.     }
  2160.     /* Object does not exist. aino points to containing directory. */
  2161.     a2 = new_child_aino (unit, a2, my_strdup (bstr_cut (unit, name2)), a1->dir ? 2 : 1);
  2162.     if (a2 == 0) {
  2163.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2164.     PUT_PCK_RES2 (packet, ERROR_DISK_FULL); /* best we can do */
  2165.     return;
  2166.     }
  2167.  
  2168.     /* @@@ what should we do if there are locks on a1? */
  2169.     if(-1 == rename(a1->nname, a2->nname)) {
  2170.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2171.     PUT_PCK_RES2 (packet, dos_errno());
  2172.     return;
  2173.     }
  2174.     move_aino_children (unit, a1, a2);
  2175.     delete_aino (unit, a1);
  2176.     PUT_PCK_RES1 (packet, DOS_TRUE);
  2177. }
  2178.  
  2179. static void
  2180. action_current_volume(Unit* unit, dpacket packet)
  2181. {
  2182.     PUT_PCK_RES1 (packet, unit->volume >> 2);
  2183. }
  2184.  
  2185. static void
  2186. action_rename_disk(Unit* unit, dpacket packet)
  2187. {
  2188.     uaecptr name = GET_PCK_ARG1 (packet) << 2;
  2189.     int i;
  2190.     int namelen;
  2191.  
  2192.     TRACE((warning_buffer, "ACTION_RENAME_DISK(\"%s\")\n", bstr (unit, name)));
  2193.  
  2194.     if(unit->ui.readonly) {
  2195.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2196.     PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
  2197.     return;
  2198.     }
  2199.  
  2200.     /* get volume name */
  2201.     namelen = get_byte (name); name++;
  2202.     free (unit->ui.volname);
  2203.     unit->ui.volname = (char *) malloc (namelen + 1);
  2204.     for(i = 0; i < namelen; i++, name++)
  2205.     unit->ui.volname[i] = get_byte (name);
  2206.     unit->ui.volname[i] = 0;
  2207.  
  2208.     put_byte (unit->volume + 44, namelen);
  2209.     for(i = 0; i < namelen; i++)
  2210.     put_byte (unit->volume + 45 + i, unit->ui.volname[i]);
  2211.  
  2212.     PUT_PCK_RES1 (packet, DOS_TRUE);
  2213. }
  2214.  
  2215. static void
  2216. action_is_filesystem(Unit* unit, dpacket packet)
  2217. {
  2218.     PUT_PCK_RES1 (packet, DOS_TRUE);
  2219. }
  2220.  
  2221. static void
  2222. action_flush(Unit* unit, dpacket packet)
  2223. {
  2224.     /* sync(); */ /* pretty drastic, eh */
  2225.     PUT_PCK_RES1 (packet, DOS_TRUE);
  2226. }
  2227.  
  2228. /* We don't want multiple interrupts to be active at the same time. I don't
  2229.  * know whether AmigaOS takes care of that, but this does. */
  2230. static uae_sem_t singlethread_int_sem;
  2231.  
  2232. static uae_u32 exter_int_helper (void)
  2233. {
  2234.     static int unit_no;
  2235.  
  2236.     switch (m68k_dreg (regs, 0)) {
  2237.      case 0:
  2238.     /* Determine whether a given EXTER interrupt is for us. */
  2239.     if (uae_int_requested) {
  2240.         if (uae_sem_trywait (&singlethread_int_sem) != 0)
  2241.         /* Pretend it isn't for us. We might get it again later. */
  2242.         return 0;
  2243.         /* Clear the interrupt flag _before_ we do any processing. 
  2244.          * That way, we can get too many interrupts, but never not
  2245.          * enough. */
  2246.         uae_int_requested = 0;
  2247.         unit_no = 0;
  2248.         return 1;
  2249.     }
  2250.     return 0;
  2251.      case 1:
  2252.     /* Release a message_lock. This is called as soon as the message is
  2253.      * received by the assembly code. We use the opportunity to check
  2254.      * whether we have some locks that we can give back to the assembler
  2255.      * code.
  2256.      * Note that this is called from the main loop, unlike the other cases
  2257.      * in this switch statement which are called from the interrupt handler.
  2258.      */
  2259.     {
  2260.         Unit *unit = find_unit (m68k_areg (regs, 5));
  2261.         unit->cmds_complete = unit->cmds_acked;
  2262.         while (comm_pipe_has_data (unit->ui.back_pipe)) {
  2263.         uaecptr locks, lockend;
  2264.         locks = read_comm_pipe_int_blocking (unit->ui.back_pipe);
  2265.         lockend = locks;
  2266.         while (get_long (lockend) != 0)
  2267.             lockend = get_long (lockend);
  2268.         put_long (lockend, get_long (m68k_areg (regs, 3)));
  2269.         put_long (m68k_areg (regs, 3), locks);
  2270.         }
  2271.     }
  2272.     break;
  2273.      case 2:
  2274.     /* Find some unit that needs a message sent, and return its port,
  2275.      * or zero if all are done.
  2276.      * Take care not to dereference self for units that didn't have their
  2277.      * startup packet sent. */
  2278.     for (;;) {
  2279.         if (unit_no >= num_units)
  2280.         return 0;
  2281.         if (ui[unit_no].self != 0
  2282.         && ui[unit_no].self->cmds_acked == ui[unit_no].self->cmds_complete
  2283.         && ui[unit_no].self->cmds_acked != ui[unit_no].self->cmds_sent)
  2284.         break;
  2285.         unit_no++;
  2286.     }
  2287.     ui[unit_no].self->cmds_acked = ui[unit_no].self->cmds_sent;
  2288.     return ui[unit_no++].self->port;
  2289.  
  2290.      case 3:
  2291.     /* Look up a message for a port. */
  2292.     {
  2293.         Unit *unit = find_unit (m68k_areg (regs, 2));
  2294.         return unit->dummy_message;
  2295.     }
  2296.     break;
  2297.      case 4:
  2298.     /* Exit the interrupt, and release the single-threading lock. */
  2299.     uae_sem_post (&singlethread_int_sem);
  2300.     break;
  2301.  
  2302.      default:
  2303.     write_log ("Shouldn't happen in exter_int_helper.\n");
  2304.     break;
  2305.     }
  2306.     return 0;
  2307. }
  2308.  
  2309. static int handle_packet (Unit *unit, dpacket pck)
  2310. {
  2311.     uae_s32 type = GET_PCK_TYPE (pck);
  2312.     PUT_PCK_RES2 (pck, 0);
  2313.     switch (type) {
  2314.      case ACTION_LOCATE_OBJECT: action_lock(unit, pck); break;
  2315.      case ACTION_FREE_LOCK: action_free_lock(unit, pck); break;
  2316.      case ACTION_COPY_DIR: action_dup_lock(unit, pck); break;
  2317.      case ACTION_DISK_INFO: action_disk_info(unit, pck); break;
  2318.      case ACTION_INFO: action_info(unit, pck); break;
  2319.      case ACTION_EXAMINE_OBJECT: action_examine_object(unit, pck); break;
  2320.      case ACTION_EXAMINE_NEXT: action_examine_next(unit, pck); break;
  2321.      case ACTION_FIND_INPUT: action_find_input(unit, pck); break;
  2322.      case ACTION_FIND_WRITE: action_find_write(unit, pck); break;
  2323.      case ACTION_FIND_OUTPUT: action_find_output(unit, pck); break;
  2324.      case ACTION_END: action_end(unit, pck); break;
  2325.      case ACTION_READ: action_read(unit, pck); break;
  2326.      case ACTION_WRITE: action_write(unit, pck); break;
  2327.      case ACTION_SEEK: action_seek(unit, pck); break;
  2328.      case ACTION_SET_PROTECT: action_set_protect(unit, pck); break;
  2329.      case ACTION_SAME_LOCK: action_same_lock(unit, pck); break;
  2330.      case ACTION_PARENT: action_parent(unit, pck); break;
  2331.      case ACTION_CREATE_DIR: action_create_dir(unit, pck); break;
  2332.      case ACTION_DELETE_OBJECT: action_delete_object(unit, pck); break;
  2333.      case ACTION_RENAME_OBJECT: action_rename_object(unit, pck); break;
  2334.      case ACTION_SET_DATE: action_set_date(unit, pck); break;
  2335.      case ACTION_CURRENT_VOLUME: action_current_volume(unit, pck); break;
  2336.      case ACTION_RENAME_DISK: action_rename_disk(unit, pck); break;
  2337.      case ACTION_IS_FILESYSTEM: action_is_filesystem(unit, pck); break;
  2338.      case ACTION_FLUSH: action_flush(unit, pck); break;
  2339.      default:
  2340.     TRACE((warning_buffer, "*** UNSUPPORTED PACKET %ld\n", type));
  2341.     return 0;
  2342.     }
  2343.     return 1;
  2344. }
  2345.  
  2346. #ifdef SUPPORT_THREADS
  2347. static void *filesys_penguin (void *unit_v)
  2348. {
  2349.     UnitInfo *ui = (UnitInfo *)unit_v;
  2350.     for (;;) {
  2351.     uae_u8 *pck;
  2352.     uae_u8 *msg;
  2353.     uae_u32 morelocks;
  2354.     int i;
  2355.  
  2356.     pck = (uae_u8 *)read_comm_pipe_pvoid_blocking (ui->unit_pipe);
  2357.     msg = (uae_u8 *)read_comm_pipe_pvoid_blocking (ui->unit_pipe);
  2358.     morelocks = (uae_u32)read_comm_pipe_int_blocking (ui->unit_pipe);
  2359.     
  2360.     if (ui->self->reset_state == FS_GO_DOWN) {
  2361.         if (pck != 0)
  2362.         continue;
  2363.         /* Death message received. */
  2364.         uae_sem_post (&ui->self->reset_sync_sem);
  2365.         /* No more messages should arrive until we restart. */
  2366.         continue;
  2367.     }
  2368.     
  2369.     put_long (get_long (morelocks), get_long (ui->self->locklist));
  2370.     put_long (ui->self->locklist, morelocks);
  2371.     if (! handle_packet (ui->self, pck)) {
  2372.         PUT_PCK_RES1 (pck, DOS_FALSE);
  2373.         PUT_PCK_RES2 (pck, ERROR_ACTION_NOT_KNOWN);
  2374.     }
  2375.     /* Mark the packet as processed for the list scan in the assembly code. */
  2376.     do_put_mem_long ((uae_u32 *)(msg + 4), -1);
  2377.     /* Acquire the message lock, so that we know we can safely send the
  2378.      * message. */
  2379.     ui->self->cmds_sent++;
  2380.     /* The message is sent by our interrupt handler, so make sure an interrupt
  2381.      * happens. */
  2382.     uae_int_requested = 1;
  2383.     /* Send back the locks. */
  2384.     if (get_long (ui->self->locklist) != 0)
  2385.         write_comm_pipe_int (ui->back_pipe, (int)(get_long(ui->self->locklist)), 0);
  2386.     put_long (ui->self->locklist, 0);
  2387.     }
  2388.     return 0;
  2389. }
  2390. #endif
  2391.  
  2392. /* Talk about spaghetti code... */
  2393. static uae_u32 filesys_handler(void)
  2394. {
  2395.     Unit *unit = find_unit (m68k_areg (regs, 5));
  2396.     uaecptr packet_addr = m68k_dreg (regs, 3);
  2397.     uaecptr message_addr = m68k_areg (regs, 4);
  2398.     uae_u8 *pck;
  2399.     uae_u8 *msg;
  2400.     if (! valid_address (packet_addr, 36) || ! valid_address (message_addr, 14)) {
  2401.     write_log ("Bad address passed for packet.\n");
  2402.     goto error2;
  2403.     }
  2404.     pck = get_real_address (packet_addr);
  2405.     msg = get_real_address (message_addr);
  2406.     
  2407.     if (unit->reset_state == FS_GO_DOWN)
  2408.     /* You might as well queue it, if you live long enough */
  2409.     return 1;
  2410.  
  2411.     do_put_mem_long ((uae_u32 *)(msg + 4), -1);
  2412.     if (!unit || !unit->volume) {
  2413.     write_log ("Filesystem was not initialized.\n");
  2414.     goto error;
  2415.     }
  2416. #ifdef SUPPORT_THREADS
  2417.     {
  2418.     /* Get two more locks and hand them over to the other thread. */
  2419.     uae_u32 morelocks;
  2420.     morelocks = get_long (m68k_areg (regs, 3));
  2421.     put_long (m68k_areg (regs, 3), get_long (get_long (morelocks)));
  2422.     put_long (get_long (morelocks), 0);
  2423.     
  2424.     /* The packet wasn't processed yet. */
  2425.     do_put_mem_long ((uae_u32 *)(msg + 4), 0);
  2426.     write_comm_pipe_pvoid (unit->ui.unit_pipe, (void *)pck, 0);
  2427.     write_comm_pipe_pvoid (unit->ui.unit_pipe, (void *)msg, 0);
  2428.     write_comm_pipe_int (unit->ui.unit_pipe, (int)morelocks, 1);
  2429.     /* Don't reply yet. */
  2430.     return 1;
  2431.     }
  2432. #endif
  2433.  
  2434.     if (! handle_packet (unit, pck)) {
  2435.      error:
  2436.     PUT_PCK_RES1 (pck, DOS_FALSE);
  2437.     PUT_PCK_RES2 (pck, ERROR_ACTION_NOT_KNOWN);
  2438.     }
  2439.     TRACE((warning_buffer, "reply: %8lx, %ld\n", GET_PCK_RES1 (pck), GET_PCK_RES2 (pck)));
  2440.  
  2441.     error2:
  2442.  
  2443.     return 0;
  2444. }
  2445.  
  2446. void filesys_reset (void)
  2447. {
  2448.     Unit *u, *u1;
  2449.     int i;
  2450.     
  2451.     for (i = 0; i < num_units; i++) {
  2452.     ui[i].self = 0;
  2453.     }
  2454.  
  2455.     for(u = units; u; u = u1) {
  2456.     u1 = u->next;
  2457.     free (u);
  2458.     }
  2459.     unit_num = 0;
  2460.     units = 0;
  2461. }
  2462.  
  2463. void filesys_prepare_reset (void)
  2464. {
  2465.     Unit *u, *u1;
  2466.     int i;
  2467.  
  2468. #ifdef SUPPORT_THREADS
  2469.     for (i = 0; i < num_units; i++) {
  2470.     if (ui[i].self != 0) {
  2471.         uae_sem_init (&ui[i].self->reset_sync_sem, 0, 0);
  2472.         ui[i].self->reset_state = FS_GO_DOWN;
  2473.         /* send death message */
  2474.         write_comm_pipe_int (ui[i].unit_pipe, 0, 0);
  2475.         write_comm_pipe_int (ui[i].unit_pipe, 0, 0);
  2476.         write_comm_pipe_int (ui[i].unit_pipe, 0, 1);
  2477.         uae_sem_wait (&ui[i].self->reset_sync_sem);
  2478.     }
  2479.     }
  2480. #endif
  2481.     u = units;
  2482.     while (u != 0) {
  2483.     while (u->rootnode.next != &u->rootnode) {
  2484.         struct a_inode *a = u->rootnode.next;
  2485.         u->rootnode.next = a->next;
  2486.         free (a->nname);
  2487.         free (a->aname);
  2488.         free (a);
  2489.     }
  2490.     u = u->next;
  2491.     }
  2492. }
  2493.  
  2494. static uae_u32 filesys_diagentry(void)
  2495. {
  2496.     uaecptr resaddr = m68k_areg(regs, 2) + 0x10;
  2497.     
  2498.     filesys_configdev = m68k_areg(regs, 3);
  2499.     
  2500.     filesys_store_devinfo (filesysory + 0x2100);
  2501.     uae_sem_init (&singlethread_int_sem, 0, 1);
  2502.     if (ROM_hardfile_resid != 0) {
  2503.     /* Build a struct Resident. This will set up and initialize
  2504.      * the uae.device */
  2505.     put_word(resaddr + 0x0, 0x4AFC);
  2506.     put_long(resaddr + 0x2, resaddr);
  2507.     put_long(resaddr + 0x6, resaddr + 0x1A); /* Continue scan here */
  2508.     put_word(resaddr + 0xA, 0x8101); /* RTF_AUTOINIT|RTF_COLDSTART; Version 1 */
  2509.     put_word(resaddr + 0xC, 0x0305); /* NT_DEVICE; pri 05 */
  2510.     put_long(resaddr + 0xE, ROM_hardfile_resname);
  2511.     put_long(resaddr + 0x12, ROM_hardfile_resid);
  2512.     put_long(resaddr + 0x16, ROM_hardfile_init); /* calls filesys_init */
  2513.     }
  2514.     resaddr += 0x1A;
  2515.  
  2516.     filesys_reset ();
  2517.     /* The good thing about this function is that it always gets called
  2518.      * when we boot. So we could put all sorts of stuff that wants to be done
  2519.      * here. */
  2520.     
  2521.     return 1;
  2522. }
  2523.  
  2524. static uae_u32 filesys_dev_remember(void)
  2525. {
  2526.     /* In: a3: devicenode, d6: unit_no */
  2527.  
  2528.     ui[m68k_dreg (regs, 6)].startup = get_long(m68k_areg (regs, 3) + 28);
  2529.     return m68k_areg (regs, 3);
  2530. }
  2531.  
  2532. /* Called exactly once, at the time we know that we are actually going
  2533.  * to run the emulator. */
  2534. void filesys_start_threads (void)
  2535. {
  2536.     int i;
  2537.     for (i = 0; i < num_units; i++) {
  2538.     int is_hardfile = ui[i].volname == 0;
  2539.     ui[i].unit_pipe = 0;
  2540. #ifdef SUPPORT_THREADS
  2541.     if (!is_hardfile) {
  2542.         ui[i].unit_pipe = (smp_comm_pipe *)malloc (sizeof (smp_comm_pipe));
  2543.         ui[i].back_pipe = (smp_comm_pipe *)malloc (sizeof (smp_comm_pipe));
  2544.         init_comm_pipe (ui[i].unit_pipe, 50, 3);
  2545.         init_comm_pipe (ui[i].back_pipe, 50, 1);
  2546.         start_penguin (filesys_penguin, (void *)(ui + i), &ui[i].tid);
  2547.     }
  2548. #endif
  2549.     }
  2550. }
  2551.  
  2552. void filesys_install (void)
  2553. {
  2554.     int i;
  2555.     uaecptr loop;
  2556.  
  2557.     ROM_filesys_resname = ds("UAEunixfs.resource");
  2558.     ROM_filesys_resid = ds("UAE unixfs 0.4");
  2559.  
  2560.     fsdevname = ds("uae.device"); /* does not really exist */
  2561.  
  2562.     for(i = 0; i < num_units; i++) {
  2563.     ui[i].devno = get_new_device(&ui[i].devname, &ui[i].devname_amiga);
  2564.     }
  2565.  
  2566.     ROM_filesys_diagentry = here();
  2567.     calltrap (deftrap(filesys_diagentry)); dw(RTS);
  2568.     
  2569.     loop = here ();
  2570.     /* Special trap for the assembly make_dev routine */
  2571.     org(0xF0FF20);
  2572.     calltrap (deftrap (filesys_dev_remember));
  2573.     dw(RTS);
  2574.  
  2575.     org(0xF0FF30);
  2576.     calltrap (deftrap (filesys_handler));
  2577.     dw(RTS);
  2578.  
  2579.     org(0xF0FF40);
  2580.     calltrap (deftrap (startup_handler));
  2581.     dw(RTS);
  2582.  
  2583.     org(0xF0FF50);
  2584.     calltrap (deftrap (exter_int_helper));
  2585.     dw(RTS);
  2586.  
  2587.     org(0xF0FF70);
  2588.     calltrap (deftrap (mousehack_helper));
  2589.     dw(RTS);
  2590.  
  2591.     org (loop);
  2592. }
  2593.  
  2594. void filesys_install_code (void)
  2595. {
  2596.     align(4);
  2597.  
  2598.     /* The last offset comes from the code itself, look for it near the top. */
  2599.     filesys_initcode = here() + 8 + 0x6c;
  2600.     EXPANSION_bootcode = here () + 8 + 0x14;
  2601.     /* Ouch. Make sure this is _always_ a multiple of two bytes. */
  2602.  db(0x00); db(0x00); db(0x00); db(0x10); db(0x00); db(0x00); db(0x00); db(0x00);
  2603.  db(0x60); db(0x00); db(0x01); db(0xda); db(0x00); db(0x00); db(0x01); db(0x2c);
  2604.  db(0x00); db(0x00); db(0x00); db(0x6c); db(0x00); db(0x00); db(0x00); db(0x28);
  2605.  db(0x00); db(0x00); db(0x00); db(0x14); db(0x43); db(0xfa); db(0x03); db(0x13);
  2606.  db(0x4e); db(0xae); db(0xff); db(0xa0); db(0x20); db(0x40); db(0x20); db(0x28);
  2607.  db(0x00); db(0x16); db(0x20); db(0x40); db(0x4e); db(0x90); db(0x4e); db(0x75);
  2608.  db(0x48); db(0xe7); db(0x00); db(0x20); db(0x70); db(0x00); db(0x4e); db(0xb9);
  2609.  db(0x00); db(0xf0); db(0xff); db(0x50); db(0x4a); db(0x80); db(0x67); db(0x2e);
  2610.  db(0x2c); db(0x78); db(0x00); db(0x04); db(0x70); db(0x02); db(0x4e); db(0xb9);
  2611.  db(0x00); db(0xf0); db(0xff); db(0x50); db(0x4a); db(0x80); db(0x67); db(0x14);
  2612.  db(0x24); db(0x40); db(0x70); db(0x03); db(0x4e); db(0xb9); db(0x00); db(0xf0);
  2613.  db(0xff); db(0x50); db(0x20); db(0x4a); db(0x22); db(0x40); db(0x4e); db(0xae);
  2614.  db(0xfe); db(0x92); db(0x60); db(0xe0); db(0x70); db(0x04); db(0x4e); db(0xb9);
  2615.  db(0x00); db(0xf0); db(0xff); db(0x50); db(0x70); db(0x01); db(0x4c); db(0xdf);
  2616.  db(0x04); db(0x00); db(0x4e); db(0x75); db(0x48); db(0xe7); db(0xff); db(0xfe);
  2617.  db(0x2c); db(0x78); db(0x00); db(0x04); db(0x2a); db(0x79); db(0x00); db(0xf0);
  2618.  db(0xff); db(0xfc); db(0x43); db(0xfa); db(0x02); db(0xb9); db(0x70); db(0x24);
  2619.  db(0x7a); db(0x00); db(0x4e); db(0xae); db(0xfd); db(0xd8); db(0x4a); db(0x80);
  2620.  db(0x66); db(0x0c); db(0x43); db(0xfa); db(0x02); db(0xa9); db(0x70); db(0x00);
  2621.  db(0x7a); db(0x01); db(0x4e); db(0xae); db(0xfd); db(0xd8); db(0x28); db(0x40);
  2622.  db(0x70); db(0x58); db(0x72); db(0x01); db(0x4e); db(0xae); db(0xff); db(0x3a);
  2623.  db(0x26); db(0x40); db(0x7e); db(0x54); db(0x27); db(0xb5); db(0x78); db(0x00);
  2624.  db(0x78); db(0x00); db(0x59); db(0x87); db(0x64); db(0xf6); db(0x7c); db(0x00);
  2625.  db(0xbc); db(0xad); db(0x01); db(0x0c); db(0x64); db(0x12); db(0x20); db(0x4b);
  2626.  db(0x48); db(0xe7); db(0x02); db(0x10); db(0x7e); db(0x01); db(0x61); db(0x6c);
  2627.  db(0x4c); db(0xdf); db(0x08); db(0x40); db(0x52); db(0x86); db(0x60); db(0xe8);
  2628.  db(0x2c); db(0x78); db(0x00); db(0x04); db(0x22); db(0x4c); db(0x4e); db(0xae);
  2629.  db(0xfe); db(0x62); db(0x61); db(0x28); db(0x2c); db(0x78); db(0x00); db(0x04);
  2630.  db(0x4e); db(0xb9); db(0x00); db(0xf0); db(0xff); db(0x80); db(0x72); db(0x03);
  2631.  db(0x74); db(0xf6); db(0x20); db(0x7c); db(0x00); db(0x20); db(0x00); db(0x00);
  2632.  db(0x90); db(0x88); db(0x65); db(0x0a); db(0x67); db(0x08); db(0x78); db(0x00);
  2633.  db(0x22); db(0x44); db(0x4e); db(0xae); db(0xfd); db(0x96); db(0x4c); db(0xdf);
  2634.  db(0x7f); db(0xff); db(0x4e); db(0x75); db(0x2c); db(0x78); db(0x00); db(0x04);
  2635.  db(0x70); db(0x1a); db(0x22); db(0x3c); db(0x00); db(0x01); db(0x00); db(0x01);
  2636.  db(0x4e); db(0xae); db(0xff); db(0x3a); db(0x22); db(0x40); db(0x41); db(0xfa);
  2637.  db(0x02); db(0x0a); db(0x23); db(0x48); db(0x00); db(0x0a); db(0x41); db(0xfa);
  2638.  db(0xff); db(0x10); db(0x23); db(0x48); db(0x00); db(0x0e); db(0x41); db(0xfa);
  2639.  db(0xff); db(0x08); db(0x23); db(0x48); db(0x00); db(0x12); db(0x70); db(0x0d);
  2640.  db(0x4e); db(0xee); db(0xff); db(0x58); db(0x2a); db(0x79); db(0x00); db(0xf0);
  2641.  db(0xff); db(0xfc); db(0x26); db(0x06); db(0xe9); db(0x8b); db(0xd6); db(0xbc);
  2642.  db(0x00); db(0x00); db(0x01); db(0x10); db(0x20); db(0x35); db(0x38); db(0x0c);
  2643.  db(0xc0); db(0x85); db(0x66); db(0xb6); db(0x20); db(0xb5); db(0x38); db(0x00);
  2644.  db(0x21); db(0x75); db(0x38); db(0x04); db(0x00); db(0x04); db(0x21); db(0x75);
  2645.  db(0x38); db(0x08); db(0x00); db(0x08); db(0x2c); db(0x4c); db(0x4e); db(0xae);
  2646.  db(0xff); db(0x70); db(0x26); db(0x40); db(0x4e); db(0xb9); db(0x00); db(0xf0);
  2647.  db(0xff); db(0x20); db(0x70); db(0x00); db(0x27); db(0x40); db(0x00); db(0x08);
  2648.  db(0x27); db(0x40); db(0x00); db(0x10); db(0x27); db(0x40); db(0x00); db(0x20);
  2649.  db(0x20); db(0x35); db(0x38); db(0x0c); db(0x4a); db(0x80); db(0x66); db(0x1c);
  2650.  db(0x27); db(0x7c); db(0x00); db(0x00); db(0x0f); db(0xa0); db(0x00); db(0x14);
  2651.  db(0x43); db(0xfa); db(0xfe); db(0x7a); db(0x20); db(0x09); db(0xe4); db(0x88);
  2652.  db(0x27); db(0x40); db(0x00); db(0x20); db(0x27); db(0x7c); db(0xff); db(0xff);
  2653.  db(0xff); db(0xff); db(0x00); db(0x24); db(0x4a); db(0x87); db(0x67); db(0x36);
  2654.  db(0x2c); db(0x78); db(0x00); db(0x04); db(0x70); db(0x14); db(0x72); db(0x00);
  2655.  db(0x4e); db(0xae); db(0xff); db(0x3a); db(0x22); db(0x40); db(0x70); db(0x00);
  2656.  db(0x22); db(0x80); db(0x23); db(0x40); db(0x00); db(0x04); db(0x33); db(0x40);
  2657.  db(0x00); db(0x0e); db(0x30); db(0x3c); db(0x10); db(0xff); db(0x90); db(0x06);
  2658.  db(0x33); db(0x40); db(0x00); db(0x08); db(0x23); db(0x6d); db(0x01); db(0x04);
  2659.  db(0x00); db(0x0a); db(0x23); db(0x4b); db(0x00); db(0x10); db(0x41); db(0xec);
  2660.  db(0x00); db(0x4a); db(0x4e); db(0xee); db(0xfe); db(0xf2); db(0x20); db(0x4b);
  2661.  db(0x72); db(0x00); db(0x22); db(0x41); db(0x70); db(0xff); db(0x2c); db(0x4c);
  2662.  db(0x4e); db(0xee); db(0xff); db(0x6a); db(0x2c); db(0x78); db(0x00); db(0x04);
  2663.  db(0x70); db(0x00); db(0x22); db(0x40); db(0x4e); db(0xae); db(0xfe); db(0xda);
  2664.  db(0x20); db(0x40); db(0x4b); db(0xe8); db(0x00); db(0x5c); db(0x43); db(0xfa);
  2665.  db(0x01); db(0x39); db(0x70); db(0x00); db(0x4e); db(0xae); db(0xfd); db(0xd8);
  2666.  db(0x24); db(0x40); db(0x20); db(0x3c); db(0x00); db(0x00); db(0x00); db(0x9d);
  2667.  db(0x22); db(0x3c); db(0x00); db(0x01); db(0x00); db(0x01); db(0x4e); db(0xae);
  2668.  db(0xff); db(0x3a); db(0x26); db(0x40); db(0x7c); db(0x00); db(0x26); db(0x86);
  2669.  db(0x27); db(0x46); db(0x00); db(0x04); db(0x27); db(0x46); db(0x00); db(0x08);
  2670.  db(0x7a); db(0x00); db(0x20); db(0x4d); db(0x4e); db(0xae); db(0xfe); db(0x80);
  2671.  db(0x20); db(0x4d); db(0x4e); db(0xae); db(0xfe); db(0x8c); db(0x28); db(0x40);
  2672.  db(0x26); db(0x2c); db(0x00); db(0x0a); db(0x70); db(0x00); db(0x4e); db(0xb9);
  2673.  db(0x00); db(0xf0); db(0xff); db(0x40); db(0x60); db(0x74); db(0x20); db(0x4d);
  2674.  db(0x4e); db(0xae); db(0xfe); db(0x80); db(0x20); db(0x4d); db(0x4e); db(0xae);
  2675.  db(0xfe); db(0x8c); db(0x28); db(0x40); db(0x26); db(0x2c); db(0x00); db(0x0a);
  2676.  db(0x66); db(0x38); db(0x70); db(0x01); db(0x4e); db(0xb9); db(0x00); db(0xf0);
  2677.  db(0xff); db(0x50); db(0x45); db(0xeb); db(0x00); db(0x04); db(0x20); db(0x52);
  2678.  db(0x20); db(0x08); db(0x67); db(0xda); db(0x22); db(0x50); db(0x20); db(0x40);
  2679.  db(0x20); db(0x28); db(0x00); db(0x04); db(0x6a); db(0x16); db(0x48); db(0xe7);
  2680.  db(0x00); db(0xc0); db(0x28); db(0x68); db(0x00); db(0x0a); db(0x61); db(0x40);
  2681.  db(0x53); db(0x85); db(0x4c); db(0xdf); db(0x03); db(0x00); db(0x24); db(0x89);
  2682.  db(0x20); db(0x49); db(0x60); db(0xdc); db(0x24); db(0x48); db(0x20); db(0x49);
  2683.  db(0x60); db(0xd6); db(0xba); db(0xbc); db(0x00); db(0x00); db(0x00); db(0x14);
  2684.  db(0x65); db(0x08); db(0x70); db(0x01); db(0x29); db(0x40); db(0x00); db(0x04);
  2685.  db(0x60); db(0x0e); db(0x61); db(0x2a); db(0x4e); db(0xb9); db(0x00); db(0xf0);
  2686.  db(0xff); db(0x30); db(0x4a); db(0x80); db(0x67); db(0x0c); db(0x52); db(0x85);
  2687.  db(0x28); db(0xab); db(0x00); db(0x04); db(0x27); db(0x4c); db(0x00); db(0x04);
  2688.  db(0x60); db(0x8c); db(0x28); db(0x43); db(0x61); db(0x02); db(0x60); db(0x86);
  2689.  db(0x22); db(0x54); db(0x20); db(0x6c); db(0x00); db(0x04); db(0x29); db(0x4d);
  2690.  db(0x00); db(0x04); db(0x4e); db(0xee); db(0xfe); db(0x92); db(0x2f); db(0x05);
  2691.  db(0x7a); db(0xfc); db(0x24); db(0x53); db(0x2e); db(0x0a); db(0x22); db(0x0a);
  2692.  db(0x67); db(0x0a); db(0x52); db(0x85); db(0x67); db(0x1e); db(0x22); db(0x4a);
  2693.  db(0x24); db(0x52); db(0x60); db(0xf2); db(0x52); db(0x85); db(0x67); db(0x3c);
  2694.  db(0x24); db(0x47); db(0x70); db(0x18); db(0x72); db(0x01); db(0x4e); db(0xae);
  2695.  db(0xff); db(0x3a); db(0x52); db(0x46); db(0x24); db(0x40); db(0x24); db(0x87);
  2696.  db(0x2e); db(0x0a); db(0x60); db(0xe8); db(0x20); db(0x12); db(0x67); db(0x24);
  2697.  db(0x20); db(0x40); db(0x20); db(0x10); db(0x67); db(0x1e); db(0x20); db(0x40);
  2698.  db(0x20); db(0x10); db(0x67); db(0x18); db(0x70); db(0x00); db(0x22); db(0x80);
  2699.  db(0x22); db(0x4a); db(0x24); db(0x51); db(0x70); db(0x18); db(0x4e); db(0xae);
  2700.  db(0xff); db(0x2e); db(0xdc); db(0xbc); db(0x00); db(0x01); db(0x00); db(0x00);
  2701.  db(0x20); db(0x0a); db(0x66); db(0xec); db(0x26); db(0x87); db(0x2a); db(0x1f);
  2702.  db(0x4e); db(0x75); db(0x55); db(0x41); db(0x45); db(0x20); db(0x66); db(0x69);
  2703.  db(0x6c); db(0x65); db(0x73); db(0x79); db(0x73); db(0x74); db(0x65); db(0x6d);
  2704.  db(0x00); db(0x64); db(0x6f); db(0x73); db(0x2e); db(0x6c); db(0x69); db(0x62);
  2705.  db(0x72); db(0x61); db(0x72); db(0x79); db(0x00); db(0x65); db(0x78); db(0x70);
  2706.  db(0x61); db(0x6e); db(0x73); db(0x69); db(0x6f); db(0x6e); db(0x2e); db(0x6c);
  2707.  db(0x69); db(0x62); db(0x72); db(0x61); db(0x72); db(0x79); db(0x00); db(0x00);
  2708. }
  2709.  
  2710. #endif